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.
Image of error:
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.
You need to return an object when doing the setup:
service.Setup(x => x.Validate(It.IsAny<IValidator<CreateExpenseCommand>>()))
.Returns(<*1>);
*1 - Here return the object that you wish to be returned when you call ValidateAsync function. Don't do It.IsAny as it returns null which causes the NullReferenceException.
Also, you need to add virtual to the ValidateAsync method in order to let it be overridable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With