Search code examples
c#unit-testingjustmock

How to mock with a IGenericRepository


I'm new in TDD developing and I've just started to do some tests with Nunit 3.7.1, Newtonsoft.Json version=10.0.3, JustMock Lite version 2016.2.426.1, C# and .NET Framework 4.7.

I want to test this class:

public class LoadFinishedTrzlBatch
{
    private IGenericRepository<ProductionOrder> proOrdRepository;
    private IGenericRepository<Batch> batchRepository;
    private IGenericRepository<Code> codeRepository;
    private IGenericRepository<Aggregation> aggregationRepository;
    private IGenericRepository<AggregationChildren> aggChildrenRepository;

    public LoadFinishedTrzlBatch(
        IGenericRepository<ProductionOrder> proOrdRepository,
        IGenericRepository<Batch> batchRepository,
        IGenericRepository<Code> codeRepository,
        IGenericRepository<Aggregation> aggregationRepository,
        IGenericRepository<AggregationChildren> aggChildrenRepository)
    {
        this.proOrdRepository = proOrdRepository;
        this.batchRepository = batchRepository;
        this.codeRepository = codeRepository;
        this.aggregationRepository = aggregationRepository;
        this.aggChildrenRepository = aggChildrenRepository;
    }

    public bool ExistsProductionOrder(string productionOrderName)
    {
        if (string.IsNullOrWhiteSpace(productionOrderName))
            throw new ArgumentNullException(nameof(productionOrderName));

        return (
            proOrdRepository
                .SearchFor(p => p.Name == productionOrderName)
                .FirstOrDefault() != null
        );
    }
}

With this test:

[TestFixture]
class LoadFinishedTrzlBatchTest
{
    private LoadFinishedTrzlBatch _load;

    [SetUp]
    public void SetUpLoadFinishedTrzlBatch()
    {
        var proOrdRepository = 
            Mock.Create<IGenericRepository<ProductionOrder>>();
        var batchRepository =
            Mock.Create<IGenericRepository<Batch>>();
        var codeRepository =
            Mock.Create<IGenericRepository<Code>>();
        var aggRepository =
            Mock.Create<IGenericRepository<Aggregation>>();
        var aggChildrenRepository =
            Mock.Create<IGenericRepository<AggregationChildren>>();

        _load = new LoadFinishedTrzlBatch(
            proOrdRepository,
            batchRepository,
            codeRepository,
            aggRepository,
            aggChildrenRepository);
    }

    [Test]
    public void ShouldExistsProductionOrder()
    {
        // Arrange
        Mock.Arrange(() => _load.ExistsProductionOrder("ProOrd"))
            .Returns(true)
            .MustBeCalled();

        // Act
        var actual = _load.ExistsProductionOrder("ProOrd");

        // Assert
        Assert.AreEqual(actual, true);
    }
}

And finally this is the IGenericRepository:

public interface IGenericRepository<TEntity>
{
    [ OMITTED ]

    IQueryable<TEntity> SearchFor(Expression<Func<TEntity, bool>> predicate);

    [ OMITTED ]
}

First, I'm not sure if this is the right way to test the method LoadFinishedTrzlBatch.ExistsProductionOrder. Everything is new for me with TDD and I'm lost.

I'm confuse of how I have mocked the IGenericRepository<ProductionOrder>. It is always be true and I'm not testing IGenericRepository<ProductionOrder>. Maybe because I'm not testing the repository.

I'm learning and I don't know what I am doing. This is why I have asked this question. I want to test ExistsProductionOrder method.

How can I test ExistsProductionOrder method?


Solution

  • You need to separate the target dependency so that it can be arranged in isolation in the test case. You also do no mock the SUT (Subject under test). You mock its dependencies. In this case you want to mock the generic repository and arrange the method being called. ie SearchFor

    Assuming that method takes a expression predicate, you can arrange the mock to expect one and then apply it to a fake collection store to mock an actual data store.

    [TestFixture]
    public class LoadFinishedTrzlBatchTest {
        private LoadFinishedTrzlBatch sut;
        //need this later so declaring as field.
        private IGenericRepository<ProductionOrder> proOrdRepository;
    
        [SetUp]
        public void SetUpLoadFinishedTrzlBatch() {  
            //Not using these so they can be declared locally          
            var batchRepository =
                Mock.Create<IGenericRepository<Batch>>();
            var codeRepository =
                Mock.Create<IGenericRepository<Code>>();
            var aggRepository =
                Mock.Create<IGenericRepository<Aggregation>>();
            var aggChildrenRepository =
                Mock.Create<IGenericRepository<AggregationChildren>>();
    
            //initializing target mock
            proOrdRepository = 
                Mock.Create<IGenericRepository<ProductionOrder>>();
    
            sut = new LoadFinishedTrzlBatch(
                proOrdRepository,
                batchRepository,
                codeRepository,
                aggRepository,
                aggChildrenRepository);
        }
    
        [Test]
        public void ShouldExistsProductionOrder()
        {
            // Arrange
            var productionOrderName = "ProOrd";
            var orders = new List<ProductionOrder>() {
                new ProductionOrder { Name = productionOrderName },
                new ProductionOrder { Name = "Dummy for Filter" }
            };
            Mock.Arrange(() => proOrdRepository
                .SearchFor(Arg.IsAny<Expression<Func<ProductionOrder,bool>>>()))
                .Returns((Expression<Func<ProductionOrder,bool>> expression) => 
                    orders.Where(expression.Compile()).AsQueryable()
                )
                .MustBeCalled();
    
            // Act
            var actual = sut.ExistsProductionOrder(productionOrderName);
    
            // Assert
            Assert.IsTrue(actual);
        }
    }