实体框架:DbContext可以被完全嘲笑吗?

时间:2016-03-10 16:17:55

标签: c# entity-framework unit-testing mocking

出于测试目的,我想创建一个自动生成的EF上下文类的模拟(DB first)。 为了做到这一点,我已经生成了一个匹配的接口,并使自动生成的类实现了这个接口(只需将接口添加到T4模板)。所以现在我的EF上下文如下所示:functions.php

IContext具有MyContext和DbContext具有的所有属性。 下一步是创建一个实现相同接口的模拟类。所以现在我也有:class MyContext : DbContext, IContext

现在针对有问题的部分:我的代码的一部分使用名为Configuration of DbContextConfiguration的DbContext属性(此属性允许我关闭"自动检测更改"功能)。问题是现在我需要为我的mock创建一个DbContextConfiguration实例,但是DbContextConfiguration只有内部构造函数,并且它没有实现任何接口。这意味着我无法直接创建它的实例,我无法继承它(感谢Microsoft)。

我已成功设法使用反射创建DbContextConfiguration实例,但不幸的是它无法使用。我可以提供有关此尝试的更多详细信息,但它就像是深入了解内部对象实例化的漏洞,我无法看到这种方法是如何工作的。

实体框架真的不可撼动,还是我可以做些什么?

2 个答案:

答案 0 :(得分:3)

在您的特定情况下,将一个方法/属性添加到您的IContext似乎是一个更好的选择,切换AutoDetectChanges功能:

public interface IContext {
    //....
    bool AutoDetectChanges { get; set; }
    bool LazyLoadingEnabled { get; set; }
    //etc..
}

你甚至可以把它包装到一些配置类:

public interface IContext {
    //....
    IContextOrmOptions Options { get; set; }

}

public interface IContextOrmOptions {
    bool AutoDetectChanges { get; set; }
    bool LazyLoadingEnabled { get; set; }
    //etc..
}

//real implementation
public class EntityFrameworkContextOrmOptions : IContextOrmOptions {
    private DbContext _dbContext;
    public EntityFrameworkContextOrmOptions(DbContext dbContext) {
        dbContext = _dbContext; 
    }
    public bool AutoDetectChanges {
        { get { return _dbContext.Configuration.AutoDetectChangesEnabled; } }
        { set { _dbContext.Configuration.AutoDetectChangesEnabled = value; } }
    }
}

不幸的是,这种方法有点打破了系统的ORM不可知性,也许有一种方法可以避免这种代码?

如果您想要模拟.Entry()方法,这也会让您遇到问题,因为它为您提供了很多方法 - 但这无论如何都很难。

答案 1 :(得分:0)

它比你想做的要简单得多,当然DbContext可以被嘲笑。这是一篇很好的文章/教程:

https://msdn.microsoft.com/en-us/library/dn314429.aspx

假设您使用的是EF 6 +