This is the method that I want to test:
public async Task<object> CreateExpense(CreateExpenseCommand command)
{
var validationResults = await _validator.ValidateAsync(command);
if (!validationResults.IsValid)
{
return validationResults.Errors.First().ToString();
}
//more code that is irrelevant for this post
}
To test this, I need to mock _validatior
, which is defined as private readonly IValidator<CreateExpenseCommand> _validator;
and is used through constructor injection.
I am using AutoFixture with AutoMoqCustomizations and Moq for mocking. Maybe I should use Moq exclusively?
This is what I try to do in the test:
[Fact]
public async Task CreateExpense_Success()
{
//Arrange
var service = _fixture.Fixture.Freeze<Mock<IValidator<CreateExpenseCommand>>>();
service.Setup(x => x.Validate((CreateExpenseCommand)It.IsAny<IValidator<CreateExpenseCommand>>())).Returns(It.IsAny<ValidationResult>);
//more code that is irrelevant for this post
}
However, this results in error:
System.NullReferenceException: 'Object reference not set to instance of an object'.
The error is pretty self-explanatory, but I don't know how to mock correctly.
I am very late to answer what solved it for me, but here goes:
namespace ExpenseTests.Application
{
public class CreateExpenseServiceTests
{
private TestFixture _fixture;
public CreateExpenseServiceTests()
{
_fixture = new TestFixture();
}
[Fact]
public async Task CreateExpense_Success()
{
//Arrange
var expense = _fixture.Fixture.Create<Expense>();
CreateExpenseCommand command = _fixture.Fixture.Build<CreateExpenseCommand>()
.With(c => c.ExpenseCategory, "HOTEL").Create();
var validationResults = _fixture.Fixture.Create<ValidationResult>();
var addMock = new Mock<ICreateExpense>();
addMock.Setup(x => x.CreateExpense(command)).ReturnsAsync(expense);
ICreateExpense addService = addMock.Object;
var validatorMock = new Mock<IValidator<CreateExpenseCommand>>();
validatorMock.Setup(x => x.Validate(It.IsAny<CreateExpenseCommand>())).Returns(validationResults);
//Act
var response = await addService.CreateExpense(command);
//Assert
Assert.Equal(typeof(Expense), response.GetType());
}
}
}
A lot of it is domain code that you can ignore. Let me know if you have further questions - hope it helps a bit.