As i said, the problem is that you are actually calling real database inside your UnitOfWork
. I'm pretty sure, your GenericRepository<>
class just wraps DbSet
inside your context. Here is where you create the 'real' database accessor.
private ContactsContext context = new ContactsContext();
But the problem is you misunderstand the whole concept of repositories. Unit of work is an abstraction of some data source. You should not unit test the abstraction, instead you should unit test some functionality which depends upon it. By the way, DbContext
itself is a Unit of work by that definition (from martinfowler.com):
Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.
Why don't people just leave it as it is? Because there is a flaw in it. Let me explain by example. Seems like you're learning ASP.Net MVC so let's write some controller:
public class ContactsController
{
public ActionResult Index(int pageSize, int currentPage)
{
using(var db = new MvcLearningContext())
{
var contacts = db.Contacts
.Skip((currentPage - 1) * pageSize)
.Take(pageSize)
.ToList();
return View(contacts);
}
}
}
As you may know, one of the great advantages of MVC is the ability to unit test controller logic. So, let's try to write a simple unit test to make sure out controller action doesn't return more entries than the given page size:
[TestMethod]
public void IndexShouldNotReturnMoreThanPageSizeResults()
{
// arrange
var controller = new ContactsController();
// act
var view = (ViewResult) controller.Index(10, 1);
// assert
var Model = (IEnumerable<Contact>) view.Model;
Assert.IsTrue(view.Model.Count() <= 10)
}
But wait... We do not want to query the real database in the unit test. Here comes the problem with EF's DbContext
: it completely depends on real database. But how can we avoid that? UnitOfWork
comes in play:
public class ContactsController
{
private UnitOfWorkFactoryBase _factory { get; set; }
public ContactsController(UnitOfWorkFactoryBase factory)
{
factory = _factory;
}
public ActionResult Index(int pageSize, int currentPage)
{
using(var db = _factory.Create())
{
var contacts = db.Contacts
.Skip((currentPage - 1) * pageSize)
.Take(pageSize)
.ToList();
return View(contacts);
}
}
}
unit test code:
[TestMethod]
public void IndexShouldNotReturnMoreThanPageSizeResults()
{
// arrange
var factory = new MockUnitOfWorkFactory();
var controller = new ContactsController(factory);
// act
var view = (ViewResult) controller.Index(10, 1);
// assert
var Model = (IEnumerable<Contact>) view.Model;
Assert.IsTrue(view.Model.Count() <= 10)
}
and in production you replace MockUnitOfWorkFactory
with UnitOfWorkFactory
UPD: basic implementation of factories:
public abstract class UnitOfWorkFactoryBase
{
public abstract UnitOfWorkBase Create();
}
public class UnitOfWorkFactory : UnitOfWorkFactoryBase
{
public override UnitOfWorkBase Create()
{
return new UnitOfWork();
}
}
public class MockUnitOfWorkFactory : UnitOfWorkFactoryBase
{
public override UnitOfWorkBase Create()
{
return new MockUnitOfWork();
}
}
UnitOfWork
and MockUnitOfWork
are implementations of UnitOfWorkBase abstract class.