Search code examples
c#.netunit-testing.net-corexunit

Unit Testing with Specification Pattern and Unit of Work is not returning data on setup


I have a generic Repository with the Unit of Work pattern setup to utilize the Specification Pattern which works great but now I am trying to Unit test it and it seems my setup isn't returning anything when specifying what to return.

Repository Snippet

 internal class Repository<T> : IRepository<T> where T : BaseEntity
{
    protected readonly ApplicationDbContext _context;

    public Repository(ApplicationDbContext context)
    {
        _context = context;
    }

    public IEnumerable<T> Find(ISpecification<T> specification = null)
    {
        return ApplySpecification(specification);
    }

    private IQueryable<T> ApplySpecification(ISpecification<T> spec)
    {
        return SpecificationEvaluator<T>.GetQuery(_context.Set<T>().AsQueryable(), spec);
    }
}

}

Snippet of Specification

public class GetStocksForCurrentDaySpecification : BaseSpecification<Stock>
    {
        public GetStocksForCurrentDaySpecification() : base(x => x.DateInserted.Day == DateTime.Today.Day) { }
    }

Snippet of me calling it

_unitOfWork.Repository<Stock>().Find(new GetStocksForCurrentDaySpecification());

This all works perfectly when running my code.

Here is my Unit Test where I do setup.

[Fact]
        public void Job_Should_Execute()
        {
            var stockList = new List<Stock>();
            stockList.Add(new Stock
            {
                Id = Guid.NewGuid(),
                DateInserted = DateTime.Now,
                Exchange = "ASX",
                LongName = "Long Name",
                MarketOpenPrice = 1.26M,
                MarketPreviousClosePrice = 1.56M,
                MarketPrice = 1.3M,
                ShortName = "Short Name",
                Symbol = "LGN"
            });

            var stockRepositoryMock = new Mock<IRepository<Stock>>();
            stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());

            var unitOfWorkMock = new Mock<IUnitOfWork>();
            unitOfWorkMock.Setup(m => m.Repository<Stock>()).Returns(stockRepositoryMock.Object).Verifiable();

            var job = new YahooStockMarketJob(new HttpClient(), unitOfWorkMock.Object, new EventPublisher(_listeners), _configuration);
            job.Execute();

            unitOfWorkMock.Verify();
        }

When debugging, the following line returns an empty array instead of an array with one item it.

// Returns empty array
 var stockRepositoryMock = new Mock<IRepository<Stock>>();
            stockRepositoryMock.Setup(m => m.Find(new GetStocksForCurrentDaySpecification())).Returns(stockList.ToArray());

enter image description here


Solution

  • In your mock object you are setting up the Find method with a specific instance of GetStocksForCurrentDaySpecification. During your test you are passing a different instance of GetStocksForCurrentDaySpecification and since those are not the same it won't use that setup.

    If you want your setup to work with your test you either need to use the same instance or allow any instance of the object by using It.IsAny<T>.

    E.g.

    // Returns empty array
    var stockRepositoryMock = new Mock<IRepository<Stock>>();
    stockRepositoryMock
        .Setup(m => m.Find(It.IsAny<GetStocksForCurrentDaySpecification>()))
        .Returns(stockList.ToArray());