jeudi 5 février 2015

Unit of Work pattern and Async operation for Testing

Following this tutorial, I've implemented Unit Of Work pattern (with Entity Framework) so that I can easily mock repository data on unit tests. That being said, I'm using async controller methods and I am having troubles on my mock repository:


Issue No. 1


The idea of Unit of Work is to handle concurrency, so the call to DbContext#SaveChangesAsync() is encapsulated by the UnitOfWork object. Now, UnitOfWork is set up to work with an IRepository interface, so that the real repository and the mock repository can be used. And here is the issue:


On the controller, when I execute an operation, let's say Create, we'd call



UnitOfWork.StudentRepository.Insert(student);
await UnitOfWork.SaveAsync();


The first line is good, since implementation of Insert() method can be different for mock repository and real. Real repository would be defined like this:



public virtual void Insert(Student student) {
schoolContext.Students.Add(student);
}


While, mock repository will be:



public virtual void Insert(Student student) {
studentList.Add(student);
}


But, the call await UnitOfWork.SaveAsync(); is not inside the repository implementation (again, cause of concurrency). So far the low-term solution I have is to only call SaveChangesAsync() if context is initialized, but it feels like smelly code.



public Task<int> SaveAsync() {
return context != null ? context.SaveChangesAsync() : new Task<int>(() => 0);
}


Issue No. 2 I have no experience whatsoever with Task<T>, so in the last code block, if the context is set to null, is it ok to return an empty task like new Task<int>(() => 0) or just return null, or is there a default convention/value?


Issue No. 3 When mocking, the generic operation TEntity GetByID(object id) is supposed to evaluate every item on the List of mocked objects and return the correct one. The problem is not every entity has the property ID, so the code below wouldn't work.



return entityList.SingleOrDefault(entity => entity.ID == id);


Is there a way different than reflection to do this (if yes, how to), considering implementing an interface for the ID property wouldn't work because of the data types.


Aucun commentaire:

Enregistrer un commentaire