shimshon
shimshon

Reputation: 344

Refactor C# entity framework 6 project to use dependancy injection for moqqing

I'm dealing with adding Dependancy Injection framework to a large project, in order to enlarge the unit testing coverage. Specially, I want to cover data access method, so I want to be able to Moq the context.

Here is a sample method:

public int GetNumberOfLines(int groupId)
{
    using (var db = new EntitiesMigrate().AutoLocal())
    {
         return db.MergeUserLines.ByGroup(groupId).GroupBy(x => x.Number).Count();
    }
}

The method AutoLocal() is an extension I've wrote that allowed us using different connection strings in each env & different dev machines. It is used on each new EntitiesMigrate() (just saying, if it can help in for moqqing). Currently we are using Microsoft test framework (inside VS/2017), but it is not a must to keep using it, for better test capabilities.

My questions are:

  1. What would be the preferred frameworks to combine DI and MOQ in an EF6 asp.net/mvc and asp.net/web-api?
  2. How to convert this method using those frameworks?

Upvotes: 2

Views: 94

Answers (1)

reckface
reckface

Reputation: 5878

I've derived an interface from my db context with IDbSets of all my entities. I inject this interface and use it for all my queries. The downside is that you have to keep this in sync with the actual db context if you make database changes.

public class EntitiesMigrate : IEntitiesMigrate
{
    public DbSet<MyEntity> MyEntities {get; set;}
    // or standardise on public IDbSet<MyEntity> MyEntities {get; set;}
    public DbSet<MergeUserLine> MergeUserLines { get; set; }
}

public interface IEntitiesMigrate
{
    DbSet<MyEntity> MyEntities {get; set;}
    // or standardise on IDbSet<MyEntity> MyEntities {get; set;}
    DbSet<MergeUserLine> MergeUserLines { get; set; }
    // Don't forget SaveChanges() and whatever else you need
}

// then remove this in your classes
using (var db = new EntitiesMigrate().AutoLocal())

// instead in your constructor
public class SomeClass
{
    public SomeClass(IEntitiesMigrate db)
    {
        _db = db;
    }
}

// then testing...
var db = new Mock<IEntitiesMigrate>();
var someOtherData = new Mock<DbSet<MergeUserLine>>(); 
// whereas IDbSet is easier to mock, DbSet will give you all the properties and methods you need. 
// see https://msdn.microsoft.com/en-us/library/dn314429(v=vs.113).aspx for setting up mock DbSets
db.Setup(d=> d.MyEntities).Returns(someData.Object);
db.Setup(d=> d.MergeUserLines).Returns(someOtherData.Object);

Your mileage may vary, but this works quite well for mocking.

Edit

I changed the IDbSet<T> to DbSet<T>

Upvotes: 1

Related Questions