0

I'm trying to write unit tests for my CQRS classes. I thought I'd start with a very simple query that returns a view model object. I want to write a test such that when I pass in a valid ID, I ensure I get the corresponding object back from the database and return the view model. I'm using FakeItEasy to fake my data access. However, all I can get back from the faked data access is an empty view model and I don't know why. What am I missing? Can anyone point me in the right direction? Below is my code:

Unit Test

public class GroupQueryTests
{
    private readonly IApplicationReadDbFacade _facade;
    private readonly CancellationToken _cancellationToken = new();

    private const string Sql = "Sql";
    private const object Param = null;
    private const IDbTransaction? Transaction = null;
    private const int ValidId = 1;
    private const string Description = "Test";
    
    public GroupQueryTests()
    {
        _facade = A.Fake<IApplicationReadDbFacade>();

        A.CallTo(() => _facade.QueryFirstOrDefaultAsync<GroupViewModel>(Sql, Param, Transaction, _cancellationToken))
            .Returns(new GroupViewModel() { Id = ValidId, Description = Description });
    }

    [Fact]
    public async void GetGroupQueryTest_ValidId_ReturnGroup()
    {
        //Arrange
        GetGroupQuery request = new();
        request.Id = ValidId;
        GetGroupQuery.GetGroupQueryHandler handler = new(_facade);

        //Act
        var g = await handler.Handle(request, _cancellationToken);

        //Assert
        Assert.IsAssignableFrom<GroupViewModel>(g);
        Assert.Equal(ValidId, g.Id);
        Assert.NotNull(g);
    }
}

Query

public class GetGroupQuery : IRequest<GroupViewModel>
{
    public int Id { get; set; }

    public class GetGroupQueryHandler : IRequestHandler<GetGroupQuery, GroupViewModel>
    {
        private readonly IApplicationReadDbFacade _facade;
        private const string Sql = @"
                SELECT TOP 1
                    Id,
                    Description
                    FROM Groups
                    WHERE Id = @Id";
         
        public GetGroupQueryHandler(IApplicationReadDbFacade facade)
        {
            _facade = facade ?? throw new ArgumentNullException(nameof(facade));
        }

        public Task<GroupViewModel> Handle(GetGroupQuery request, CancellationToken cancellationToken) =>
            _facade.QueryFirstOrDefaultAsync<GroupViewModel>(Sql, request, cancellationToken: cancellationToken);
    }
}

The test above fails when asserting if the returned group Id from the query is equal to the Id passed int the query. Any help would be much appreciated.

Thanks.

Jester1811
  • 23
  • 5

1 Answers1

0

The argument matchers of your fake configuration is not appropriate. Your configuration requires the request parameter to be null exactly; but you are passing a GetGroupQuery instance in your call. As a result, your invocation is not matching the fake you configured.

FakeItEasy allows ignoring arguments whose values do not matter in a method's execution. In your case, you could have ignored the request parameter (maybe few others too) by changing the configuration to this: A.CallTo(() => _facade.QueryFirstOrDefaultAsync<GroupViewModel>(Sql, A<GetGroupQuery>.ignored, Transaction, _cancellationToken)). The updated configuration matches calls with any GetGroupQuery instance passed as request parameters.

Farhan Nasim
  • 773
  • 4
  • 13
  • Thanks Farhan. I actually opted for a different approach in the end and used a copy of my production db for testing in the end as that gave me more confidence the thing would work in the real world. – Jester1811 Jul 02 '22 at 20:08