I decided to start writing unit tests in our application. It uses Entity Framework with a repository pattern.
Now I want to start testing logic classes which are using the repositories. I provide a simple example here.
Three of my methods in the class GenericRepository:
public class GenericRepository : IRepository
{
public IQueryable<TEntity> GetQuery<TEntity>() where TEntity : class
{
var entityName = GetEntityName<TEntity>();
return Context.CreateQuery<TEntity>(entityName);
}
private string GetEntityName<TEntity>() where TEntity : class
{
return typeof(TEntity).Name;
}
public IEnumerable<TEntity> Find<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return GetQuery<TEntity>().Where(predicate).AsEnumerable();
}
}
A simple logic class returning distinct years from a calendar table in descending order (yes I know the word calendar is misspelled in our code):
public class GetDistinctYearsFromCalendar
{
private readonly IRepository _repository;
public GetDistinctYearsFromCalendar()
{
_repository = new GenericRepository();
}
internal GetDistinctYearsFromCalendar(IRepository repository)
{
_repository = repository;
}
public int[] Get()
{
return _repository.Find<Calender_Tbl>(c => c.Year.HasValue).Select(c => c.Year.Value).Distinct().OrderBy(c => c).Reverse().ToArray();
}
}
And here is my first test:
[TestFixture]
public class GetDistinctYearsFromCalendarTest
{
[Test]
public void ReturnsDistinctDatesInCorrectOrder()
{
var repositoryMock = new Mock<IRepository>();
repositoryMock.Setup(r => r.Find<Calender_Tbl>(c => c.Year.HasValue)).Returns(new List<Calender_Tbl>
{
new Calender_Tbl
{
Date =
new DateTime(2010, 1, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2010, 2, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2011, 1, 1),
Year = 2011
}
}.AsQueryable());
var getDistinct = new GetDistinctYearsFromCalendar(repositoryMock.Object).Get();
Assert.AreEqual(2, getDistinct.Count(), "Returns more years than distinct.");
Assert.AreEqual(2011, getDistinct[0], "Incorrect order, latest years not first.");
Assert.AreEqual(2010, getDistinct[1], "Wrong year.");
}
}
This is working fine. But this is not actually what I want to do. Since I have to setup the method Find on the mock object I also need to know how it is going to be called in my logic class. If I would like to do TDD I don't want to mind about this. All I want to know is which Calendar entities my repository should provide. I would like to setup the GetQuery method. Like this:
repositoryMock.Setup(r => r.GetQuery<Calender_Tbl>()).Returns(new List<Calender_Tbl>
{
new Calender_Tbl
{
Date =
new DateTime(2010, 1, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2010, 2, 1),
Year = 2010
},
new Calender_Tbl
{
Date =
new DateTime(2011, 1, 1),
Year = 2011
}
}.AsQueryable());
So when Find is calling GetQuery internally in the GenericRepository class it should get the correct Calendar entities that I setup in GetQuery. But this is not working of course. Since I haven't setup the Find method of my mock object I don't get any entities.
So what to do? Of course I could probably use Moles or some other framework which mocks everything but I don't want to do that. Is there anything I can do in the design of the class or test to solve the issue?
It is not the end of the world if I have to go with my current solution but what if the property year turns into a not nullable int? Then of course I will have to change my implementation in the logic class but I would also have to change the test. I would like to try to avoid this.