Unit Testing Object with Two EF-6 Contexts

Introduction

As I’ve mentioned before, I work for DealerOn.  Our development environment is organized by some very intelligent software developers who are pushing the envelope on technological advances in our software.  One of the development strategies is to use as much automated testing as possible.  So we’re all learning what the Microsoft test environment is capable of and what its limitations are.  One problem that was encountered recently by a new developer of ours is how to test a method that contains two EF-6 queries to two different contexts.

So I opened up my Visual Studio project that I used to create the EF-6 unit testing blog post about a month ago and started copying and pasting code until I got it to work the way I expected it to.

Shut-up and Show Me an Example!

OK, here’s an object and one method I created using two EF-6 frameworks (I’ll leave it to the reader to create two EF-6 edmx files with context names called AccountingContext with a table called account and another called DepartmentContext with a table called department). 

public class DepartmentsAndAccounts
{
    private DepartmentContext _DeptContext;
    private AccountingContext _AccountContext;


    public DepartmentsAndAccounts(
           DepartmentContext deptContext,
           AccountingContext accountContext)
    {
        _DeptContext = deptContext;
        _AccountContext = accountContext;
    }


    public int TotalDeptAndAccountRecords()
    {
        var deptQuery = (from dept

                         in _DeptContext.departments
                         select dept.name).ToList();

        var accountQuery = (from acct
                            in _AccountContext.accounts
                            select acct.username).ToList();

        int result = deptQuery.Count() + accountQuery.Count();
        return result;
    }
}

As you can see, I needed to pass the two contexts into the initializer.  These contexts are two separate objects so they must be passed in separately and saved for use with their own tables.  If any reader has a more elegant method of handling this, please leave me a message and I’ll do a follow-up post.

Now it’s time to setup the unit test.  Basically, I just mocked two separate tests and called the DepartmentsAndAccounts object at the end of the test.  Here’s the entire unit test method:

[TestMethod]
public void TestTwoContexts()
{
    //account table
    var accountData = new List<account>
    {
        new account { username = “test“,pass=”testpass1” },
        new account { username = “ZZZ“,pass=”testpass2” },
        new account { username = “AAA“,pass=”testpass3” }
    }.AsQueryable();


    var accountMockSet = new Mock<DbSet<account>>();
    accountMockSet.As<IQueryable<account>>().Setup(m => m.Provider)
        .Returns(accountData.Provider);
    accountMockSet.As<IQueryable<account>>().Setup(m => m.Expression)
        .Returns(accountData.Expression);
    accountMockSet.As<IQueryable<account>>().Setup(m => m.ElementType)
        .Returns(accountData.ElementType);
    accountMockSet.As<IQueryable<account>>().Setup(m => m.GetEnumerator())
        .Returns(accountData.GetEnumerator());


    var accountMockContext = new Mock<AccountingContext>();
    accountMockContext.Setup(c => c.accounts).Returns(accountMockSet.Object);


    // department table
    var deptData = new List<department>
    {
        new department {name=”Operations“},
        new department {name=”Sales“}
    }.AsQueryable();


    var deptMockSet = new Mock<DbSet<department>>();
    deptMockSet.As<IQueryable<department>>().Setup(m => m.Provider)

        .Returns(deptData.Provider);
    deptMockSet.As<IQueryable<department>>().Setup(m => m.Expression)
        .Returns(deptData.Expression);
    deptMockSet.As<IQueryable<department>>().Setup(m => m.ElementType)
        .Returns(deptData.ElementType);
    deptMockSet.As<IQueryable<department>>().Setup(m => m.GetEnumerator())
        .Returns(deptData.GetEnumerator());


    var deptMockContext = new Mock<DepartmentContext>();
    deptMockContext.Setup(c => c.departments)

        .Returns(deptMockSet.Object);

    DepartmentsAndAccounts deptAndAccts =
        new DepartmentsAndAccounts(deptMockContext.Object, accountMockContext.Object);
    int total = deptAndAccts.TotalDeptAndAccountRecords();


    Assert.AreEqual(5, total, “total does not equal expected value“);
}


As you can see from the code, I mocked up two different contexts by using a copy and paste and renamed the variables (these came from code used in the previous blog article).  The result should be the total count of both tables, which should be 5 (3 records in account and 2 records in department).  You can alter your assert to test for the result you’re expecting from the method you have under test.

 

Leave a Reply