Search code examples
c#.netunit-testingin-memory-database

Unit Test for a Query Handler with InMemoryDatabase and Generic Repository Pattern


I have a Generic Repository Pattern that receive the domain as Generic Type and I am creating a Unit Test for my Query Handler and using InMemoryDatabase.

The code below it's a reference for this post and I implemented it for my case.

public class ContractTypeSeedDataFixture : IDisposable
{
    public Fixture _fixture = new();

    public PaperclipContext PaperclipContext { get; private set; }

    const string BILLS_OPERATION_TIME = "{ \"id\": 3... }";
    const string TAX_OPERATION_TIME = "{ \"id\": 6... }";
    const string PIX_OPERATION_TIME = "{ \"id\": 1... }";

    public ContractTypeSeedDataFixture()
    {
        var options = new DbContextOptionsBuilder<PaperclipContext>()
            .UseInMemoryDatabase(databaseName: "unitTestDatabase")
            .Options;

        PaperclipContext = new PaperclipContext(options);

        _fixture.Behaviors.Remove(new ThrowingRecursionBehavior());
        _fixture.Behaviors.Add(new OmitOnRecursionBehavior());
        
        _fixture.Register(() => _fixture.Build<List<Func<IDomainEvent>>>().Create());
        _fixture.Register(() => _fixture.Build<DefaultContractNotifications>().Create());

        PaperclipContext.ContractType.Add(_fixture.Build<ContractType>().With(p => p.OperationTime, BILLS_OPERATION_TIME).Create());
        PaperclipContext.ContractType.Add(_fixture.Build<ContractType>().With(p => p.OperationTime, TAX_OPERATION_TIME).Create());
        PaperclipContext.ContractType.Add(_fixture.Build<ContractType>().With(p => p.OperationTime, PIX_OPERATION_TIME).Create());
        PaperclipContext.ContractType.Add(_fixture.Build<ContractType>().Without(p => p.OperationTime).Create());
        PaperclipContext.SaveChanges();
    }

    public void Dispose()
    {
        PaperclipContext.Dispose();
    }
}

This part that's fine because I put a breakpoint and returned the data that I added using the ContractTypeSeedDataFixture.

[Fact(DisplayName = "Should return contractTypeOperationTimeViewModel ordered by id.")]
public async Task Get_OperationTime_ReturnContractTypeOperationTimeViewModel()
{
    // Arrange
    var t = _contractTypeSeedDataFixture.PaperclipContext.ContractType.ToList();    
}

To know, the Query Handler that I want to test it's the code below. Then I get IRepository<domain.Entities.ContractType> _contractTypeRepository in my constructor

public async Task<IOrderedEnumerable<ContractTypeOperationTimeViewModel>> Handle(GetContractTypeOperationTimeQuery request, CancellationToken cancellationToken)
{
    var contractsTypeOperation = _contractTypeRepository
        .List()
        .AsNoTracking()
        .Where(cT => cT.OperationTime != null)
        .Select(cT => JsonConvert.DeserializeObject<ContractTypeOperationTimeViewModel>(cT.OperationTime))
        .AsEnumerable()
        OrderBy(cT => cT.Id);

        return await Task.FromResult(contractsTypeOperation);
}

The test that I am creating it's below

public class GetContractTypeOperationTimeQueryHandlerTests : IClassFixture<ContractTypeSeedDataFixture>
{
    private readonly ContractTypeSeedDataFixture _contractTypeSeedDataFixture = new();
    private readonly IRepository<Domain.ContractType> _contractTypeRepository;

    public GetContractTypeOperationTimeQueryHandlerTests(ContractTypeSeedDataFixture contractTypeSeedDataFixture)
    {
        _contractTypeSeedDataFixture = contractTypeSeedDataFixture;
    }


    [Fact(DisplayName = "Should return contractTypeOperationTimeViewModel ordered by id.")]
    public async Task Get_OperationTime_ReturnContractTypeOperationTimeViewModel()
    {
        // Arrange

        // Act
        var getContractTypeOperationTimeQuery = new GetContractTypeOperationTimeQuery();
        var getContractTypeOperationTimeQueryHandler = new GetContractTypeOperationTimeQueryHandler(_contractTypeRepository);
        var contractTypeOperationTimeViewModel = await getContractTypeOperationTimeQueryHandler.Handle(getContractTypeOperationTimeQuery, new CancellationToken());


        // Assert
        Assert.Equal(1, contractTypeOperationTimeViewModel.First().Id);
        //contractTypeOperationTimeViewModel.Should().BeInAscendingOrder(compare => compare.Id);
    }
}

But the problem is that when I run the test, in the Query Handler, the _contractTypeRepository it's null, but I think, why it's null if I am using some seed fixture to generate my data?

I tried to send the IRepository in the constructor.

I created a specific repository and it's worked but here we use generic repository pattern.


Solution

  • You need to initialize your repository variable:

    _contractTypeRepository = new Repository<Domain.ContractType>(_contractTypeSeedDataFixture.PaperclipContext); 
    

    Whole class example:

    public class GetContractTypeOperationTimeQueryHandlerTests : IClassFixture<ContractTypeSeedDataFixture>
    {
        private readonly ContractTypeSeedDataFixture _contractTypeSeedDataFixture = new();
        private readonly IRepository<Domain.ContractType> _contractTypeRepository = new Repository<Domain.ContractType>(_contractTypeSeedDataFixture.PaperclipContext);
    
        public GetContractTypeOperationTimeQueryHandlerTests(ContractTypeSeedDataFixture contractTypeSeedDataFixture)
        {
            _contractTypeSeedDataFixture = contractTypeSeedDataFixture;
        }
    
    
        [Fact(DisplayName = "Should return contractTypeOperationTimeViewModel ordered by id.")]
        public async Task Get_OperationTime_ReturnContractTypeOperationTimeViewModel()
        {
            // Arrange
    
            // Act
            var getContractTypeOperationTimeQuery = new GetContractTypeOperationTimeQuery();
            var getContractTypeOperationTimeQueryHandler = new GetContractTypeOperationTimeQueryHandler(_contractTypeRepository);
            var contractTypeOperationTimeViewModel = await getContractTypeOperationTimeQueryHandler.Handle(getContractTypeOperationTimeQuery, new CancellationToken());
    
    
            // Assert
            Assert.Equal(1, contractTypeOperationTimeViewModel.First().Id);
            //contractTypeOperationTimeViewModel.Should().BeInAscendingOrder(compare => compare.Id);
        }
    }