Question

This is my test:

[TestMethod]
public void TestUnitOfWork()
{
    UnitOfWork unitOfWork = new UnitOfWork();

    unitOfWork.ContactRepository.Insert(new Contact
    {
        Id = Guid.NewGuid(),
        FirstName = "Dom",
        LastName = "A",
        Email = "dominicarchual@yahoo.com"
    });

    var contacts = unitOfWork.ContactRepository.Get(x => x.FirstName == "Dominic");

    Assert.AreEqual(1, contacts.Count());
}

The error I get is:

Test method MvcContacts.Tests.Controllers.HomeControllerTest.TestUnitOfWork threw exception: System.Data.ProviderIncompatibleException: An error occurred while getting provider information from the database. This can be caused by Entity Framework using an incorrect connection string. Check the inner exceptions for details and ensure that the connection string is correct. ---> System.Data.ProviderIncompatibleException: The provider did not return a ProviderManifestToken string. ---> System.Data.SqlClient.SqlException: A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)

I don't have any database set up; i.e. my context looks like this:

namespace MvcContacts.DAL
{
    public class ContactsContext : DbContext
    {
        public DbSet<Contact> Contacts { get; set; }
    }
}

I don't know exactly how to map this to my database; but, I was thinking that I wouldn't have to do that yet since I am just trying to test using mock data. Am I wrong?

E1: This is my unit of work class.

namespace MvcContacts.DAL
{
    public class UnitOfWork : IDisposable
    {
        private ContactsContext context = new ContactsContext();
        private GenericRepository<Contact> contactRepository;

        public GenericRepository<Contact> ContactRepository
        {
            get
            {
                if (this.contactRepository == null)
                {
                    this.contactRepository = new GenericRepository<Contact>(context);
                }
                return contactRepository;
            }
        }

        public void Save()
        {
            context.SaveChanges();
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
}
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top