I'm writing unit tests for my services using autofixture and autodata. This is the test.
[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);
}
And this the service method being tested
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);
}
As you can see, i setup repository used in service to return null if any int is passed so that i can check that the service properly throws my custom exception with my constant error message. Then i create a delegate of my method and test what i need. But the test fails with message:
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 ---
I've tested manually and the method works as expected so I think the problem is with autofixture setups, but cant understand it exactly yet. Here is AutoMoqDataAttribute in case it helps
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(CreateFixture)
{
}
private static IFixture CreateFixture()
{
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization { ConfigureMembers = true });
return fixture;
}
}
Update: solution for TR;DR: change
IServicetoService.Explanation: debugging has shown that if you pass interface of the service instead of the actual class, then autofixture will create
Mock<IService>which will not act the way it is supposed to, so either changeIServicetoServiceor in case you really want to use service you can create customization like thatBut it really isn't preferable since you want to test actual service