thesystem
thesystem

Reputation: 604

How to mock FluentValidation ValidationResults in test

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:enter image description here

Upvotes: 3

Views: 5854

Answers (2)

thesystem
thesystem

Reputation: 604

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.

Upvotes: 2

Misha Zaslavsky
Misha Zaslavsky

Reputation: 9702

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.

Upvotes: 1

Related Questions