Reputation: 21807
Given a basic repository interface:
public interface IPersonRepository
{
void AddPerson(Person person);
List<Person> GetAllPeople();
}
With a basic implementation:
public class PersonRepository: IPersonRepository
{
public void AddPerson(Person person)
{
ObjectContext.AddObject(person);
}
public List<Person> GetAllPeople()
{
return ObjectSet.AsQueryable().ToList();
}
}
How can you unit test this in a meaningful way? Since it crosses the boundary and physically updates and reads from the database, thats not a unit test, its an integration test.
Or is it wrong to want to unit test this in the first place? Should I only have integration tests on the repository?
I've been googling the subject and blogs often say to make a stub that implements the IRepository:
public class PersonRepositoryTestStub: IPersonRepository
{
private List<Person> people = new List<Person>();
public void AddPerson(Person person)
{
people.Add(person);
}
public List<Person> GetAllPeople()
{
return people;
}
}
But that doesnt unit test PersonRepository, it tests the implementation of PersonRepositoryTestStub (not very helpful).
Upvotes: 5
Views: 1521
Reputation: 4953
I have run into the same problem. I wrote a slew of unit tests against an implementation of my repository interface that was a fake repository. Shortly after completing it, I realized that I wrote the unit test to test the fake repository and I wrote the fake repository simply to support the unit tests. This seemed like a large amount of useless code.
I have come to the conclusion that I don't need the unit tests but that the fake repository implementation is good because I can use it as the repository my services (and therefore my controllers) use so that unit tests against those will be predictable (thanks to a predefined fake repository).
So, I have decided to leave the unit tests against the fake repository in there as they are helpful to test my fake repository so that I can be assured that the higher levels of my application are using fully tested fakes.
In other words, the fake repository and the unit tests against the fake repository are the "supporting cast" for higher levels of the applications and the unit tests against higher levels of the application.
Hope that helps.
Upvotes: 2
Reputation: 7750
I would test Business Logic layer that depends on DAL implementation directly (has strong reference to DAL exact implementation) or indirectly (abstracted from DAL via interfaces).
I am not very fond of tests, that uses stub implementation, just wrap database calls into uncomitted transaction (that rolls back all data changes when test finishes even if exception is thrown).
Upvotes: 0
Reputation: 191
The time when I think this type of testing makes sense is when your repository interface is generic. E.g.
public interface IEntity
{
int Id { get; set; }
}
public interface IRepository<TEntity>
where TEntity : IEntity
{
void Add(TEntity entity);
List<TEntity> GetAll();
}
If you have multiple implementations of that interface, then it is also possible to write a generic test fixture that tests against that interface, allowing you to test multiple repository implementations with a single test fixture. This approach does not differentiate between unit and integration tests, because it has no idea what the implementation is.
Let me know if this type of thing interests you and I can post a complete example.
Upvotes: 1
Reputation: 4124
In this specific case I think you don't need to make a unit test for your repository class, as the implementation is simply invoking the ObjectContext
object, so it will be like testing something you didn't build (which is not the idea). In case you don't have any complex logic, my recommendation is not to waste time on making a unit test for that class. What you say about the PersonRepositoryTestStub is a fake implementation of the repository for testing the layer that is above of your DAL.
Upvotes: 7