Link to home
Start Free TrialLog in
Avatar of dyarosh
dyarosh

asked on

Using FakeDbSet without modify DbContext entity when using EF 5

I am investigating TDD with my MVC 4 application that uses Entity Framework 5.0 (Code First).  I followed the example at this link, http://www.nogginbox.co.uk/blog/mocking-entity-framework-data-context, to make the modifications to my application to get it to work.  Making the changes mentioned in the link I was able to get my unit tests to work using a "Fake" database and also to get the application to work connecting to the database.

My problem is the instructions have me changing the DbContext file generated by the EF Designer.  The changes needed include:
Derive from DbContext and my Interface
replace DbSet with IDbSet on my properties

Now whenever my model changes and the DbContext file is regenerated my changes are lost.

Can someone suggest a way of getting around this?  Any help is greatly appreciated!

I am including the code so you can see what is going on.

auto-generated DbContext file with my manual changes:
namespace AppCatalog.Models
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    
    public partial class AppCatalogContainer : DbContext, IAppCatalogContainer
    {
        public AppCatalogContainer()
            : base("name=AppCatalogContainer")
        {
        }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }
    
        public IDbSet<AppCatalog_Database> AppCatalog_Database { get; set; }
        public IDbSet<AppCatalog_ServerType> AppCatalog_ServerType { get; set; }
        public IDbSet<AppCatalog_DBConnection> AppCatalog_DBConnection { get; set; }
        public IDbSet<AppCatalog_Environment> AppCatalog_Environment { get; set; }
        public IDbSet<AppCatalog_PIIData> AppCatalog_PIIData { get; set; }
        public IDbSet<AppCatalog_Application> AppCatalog_Application { get; set; }
        public IDbSet<AppCatalog_ApplicationTable> AppCatalog_ApplicationTable { get; set; }
    }
}

Open in new window


My Interface
using System;
using System.Data.Entity;

namespace AppCatalog.Models 
{
    public interface IAppCatalogContainer 
    {
        IDbSet<AppCatalog_Database> AppCatalog_Database { get; set; }
        IDbSet<AppCatalog_ServerType> AppCatalog_ServerType { get; set; }
        IDbSet<AppCatalog_DBConnection> AppCatalog_DBConnection { get; set; }
        IDbSet<AppCatalog_Environment> AppCatalog_Environment { get; set; }
        IDbSet<AppCatalog_PIIData> AppCatalog_PIIData { get; set; }
        IDbSet<AppCatalog_Application> AppCatalog_Application { get; set; }
        IDbSet<AppCatalog_ApplicationTable> AppCatalog_ApplicationTable { get; set; }

        int SaveChanges();
        void Dispose();
     }
}

Open in new window


FakeDbSet.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Entity;
using System.Collections.ObjectModel;
using System.Linq.Expressions;
using System.Collections;

namespace AppCatalog.Tests.Controllers
{
    public class FakeDbSet<T> : IDbSet<T> where T : class
    {
        HashSet<T> _data;
        IQueryable _query;

        public FakeDbSet()
        {
            _data = new HashSet<T>();
            _query = _data.AsQueryable();
        }


        public virtual T Find(params object[] keyValues)
        {
            throw new NotImplementedException("Derive from FakeDbSet<T> and override Find");
        }

        public T Add(T item)
        {
            _data.Add(item);
            return item;
        }

        public T Remove(T item)
        {
            _data.Remove(item);
            return item;
        }

        public void DeleteObject(T item)
        {
            _data.Remove(item);
        }

        public T Attach(T item)
        {
            _data.Add(item);
            return item;
        }

        public void Detach(T item)
        {
            _data.Remove(item);
        }

        public T Create()
        {
            return Activator.CreateInstance<T>();
        }

        public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
        {
            return Activator.CreateInstance<TDerivedEntity>();
        }

        public ObservableCollection<T> Local
        {
            get { return new ObservableCollection<T>(_data); }
        }

        Type IQueryable.ElementType
        {
            get { return _query.ElementType; }
        }

        Expression IQueryable.Expression
        {
            get { return _query.Expression; }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return _query.Provider; }
        }

        IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return _data.GetEnumerator();
        }

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return _data.GetEnumerator();
        }

    }
}

Open in new window


My Controller:
namespace AppCatalog.Controllers
{
    public class DBCatalogController : Controller
    {
        private IAppCatalogContainer db { get; set; }

        public DBCatalogController(IAppCatalogContainer dataContext = null)
        {
            db = dataContext ?? new AppCatalogContainer();
        }
        public DBCatalogController()
        {
            db = new AppCatalogContainer();
        }

        //
        // GET: /DBCatalog/

        public ViewResult Index()
        {
            ViewBag.Title = "Application Catalog -> Database Catalog";

            var appcatalog_database = db.AppCatalog_Database.Include(a => a.AppCatalog_ServerType);
            return View(appcatalog_database.ToList());
        }
    }
}

Open in new window


My Test using Moq and FakeDbSet:
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using AppCatalog.Controllers;
using System.Web.Mvc;
using AppCatalog.Models;
using System.Data.Entity;
using Moq;

namespace AppCatalog.Tests.Controllers
{
    [TestClass]
    public class DBCatalogControllerTest
    {
        [TestMethod]
        public void VerifyTitleIsApplicationCatalogDatabaseCatalog()
        {
            // Create Fake Data
            var inMemoryItems = new FakeDbSet<AppCatalog_Database>
            {
                new AppCatalog_Database { databaseID=1, databaseName="AppCatalog", databaseDescription="Contains tables used by Application Catalog app", databaseServerTypeID=2 },
                new AppCatalog_Database { databaseID=2, databaseName="EMP_OWNER", databaseDescription="Contains tables used by Employee Profile app", databaseServerTypeID=1 }
            };

            // Create mock unit of work
            var mockData = new Mock<IAppCatalogContainer>();
            mockData.Setup(m => m.AppCatalog_Database).Returns(inMemoryItems);

            // Setup controller
            DBCatalogController controller = new DBCatalogController(mockData.Object);

            // Invoke
            ViewResult viewResult = controller.Index();

            // Assert
            Assert.AreEqual("Application Catalog -> Database Catalog", viewResult.ViewBag.Title);
        }

        [TestMethod]
        public void VerifyDatabaseReturnsAllRecords()
        {
            // Create Fake Data
            var inMemoryItems = new FakeDbSet<AppCatalog_Database>
            {
                new AppCatalog_Database { databaseID=1, databaseName="AppCatalog", databaseDescription="Contains tables used by Application Catalog app", databaseServerTypeID=2 },
                new AppCatalog_Database { databaseID=2, databaseName="EMP_OWNER", databaseDescription="Contains tables used by Employee Profile app", databaseServerTypeID=1 }
            };

            // Create mock unit of work
            var mockData = new Mock<IAppCatalogContainer>();
            mockData.Setup(m => m.AppCatalog_Database).Returns(inMemoryItems);

            // Setup controller
            DBCatalogController controller = new DBCatalogController(mockData.Object);

            // Invoke
            ViewResult viewResult = controller.Index();
            var model = viewResult.Model as IEnumerable<AppCatalog_Database>;

            Assert.AreEqual(2, model.Count());
        }
    }
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Mihai Stancescu
Mihai Stancescu
Flag of Romania image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of dyarosh
dyarosh

ASKER

Thank you for the response.  I reviewed the link and think that it will work perfectly for my situation.  I am going to backup and use the repository pattern.
Glad I could help you.

Have a nice day,
Mishu