我正在使用自动固定装置和自动数据为我的服务编写单元测试。这就是测试。
[Theory]
[AutoMoqData]
public async Task GetByIdAsync_WhenInvalidId_ShouldThrowNotFoundException(
Mock<IReviewRepository> repositoryMock,
IReviewService service)
{
// Arrange
repositoryMock.Setup(r => r.GetByIdAsync(It.IsAny<int>()))
.ReturnsAsync(value: null);
// Act
var act = () => service.GetByIdAsync(It.IsAny<int>());
await act.Should().ThrowAsync<NotFoundException>()
.WithMessage(ErrorMessages.REVIEW_NOT_FOUND);
}
这就是正在测试的服务方法
public async Task<Review> GetByIdAsync(int id)
{
var foundReview = await _repository.GetByIdAsync(id);
if (foundReview == null)
{
Log.Error("Review with id = {@id} not found", id);
throw new NotFoundException(ErrorMessages.REVIEW_NOT_FOUND);
}
return _mapper.Map<Review>(foundReview);
}
如您所见,我设置了服务中使用的存储库,以便在传递任何 int 时返回 null,以便我可以检查服务是否正确抛出我的自定义异常以及恒定的错误消息。 然后我创建我的方法的委托并测试我需要的内容。但测试失败并显示消息:
Message:
Expected a <SecondMap.Services.StoreManagementService.BLL.Exceptions.NotFoundException> to be thrown, but no exception was thrown.
Stack Trace:
XUnit2TestFramework.Throw(String message)
TestFrameworkProvider.Throw(String message)
DefaultAssertionStrategy.HandleFailure(String message)
AssertionScope.FailWith(Func`1 failReasonFunc)
AssertionScope.FailWith(Func`1 failReasonFunc)
AssertionScope.FailWith(String message)
DelegateAssertionsBase`2.ThrowInternal[TException](Exception exception, String because, Object[] becauseArgs)
AsyncFunctionAssertions`2.ThrowAsync[TException](String because, Object[] becauseArgs)
ExceptionAssertionsExtensions.WithMessage[TException](Task`1 task, String expectedWildcardPattern, String because, Object[] becauseArgs)
ReviewServiceTests.GetByIdAsync_WhenInvalidId_ShouldThrowNotFoundException(Mock`1 repositoryMock, IReviewService service) line 59
--- End of stack trace from previous location ---
我已经手动测试过,该方法按预期工作,所以我认为问题出在自动夹具设置上,但还不能完全理解它。这是 AutoMoqDataAttribute 以防有帮助
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(CreateFixture)
{
}
private static IFixture CreateFixture()
{
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
return fixture;
}
}
更新:TR;DR的解决方案:将IService更改为Service。 说明:调试表明,如果您传递服务的接口而不是实际的类,则 autofixture 将创建 Mock,而该 Mock 不会按照预期的方式运行,因此要么将 IService 更改为 Service,要么如果您确实想使用服务你可以像这样创建定制
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(CreateFixture)
{
}
private static IFixture CreateFixture()
{
var fixture = new Fixture();
fixture.Customize(new CompositeCustomization(
new AutoMoqCustomization { ConfigureMembers = true },
new ServiceCustomization()));
return fixture;
}
}
public class ServiceCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
fixture.Register<IReviewService>(CreateReviewService);
fixture.Register<IScheduleService>(CreateScheduleService);
fixture.Register<IStoreService>(CreateStoreService);
fixture.Register<IUserService>(CreateUserService);
}
private static ReviewService CreateReviewService() => new ReviewService(new Mock<IReviewRepository>().Object, new Mock<IMapper>().Object);
private static ScheduleService CreateScheduleService() => new ScheduleService(new Mock<IScheduleRepository>().Object, new Mock<IMapper>().Object);
private static StoreService CreateStoreService() => new StoreService(new Mock<IStoreRepository>().Object, new Mock<IMapper>().Object);
private static UserService CreateUserService() => new UserService(new Mock<IUserRepository>().Object, new Mock<IMapper>().Object);
}
但这确实不是优选的,因为你想测试实际服务