3

从我经常阅读的实体框架中读取/写入上下文时,建议尽可能缩短上下文的生命周期(每个工作单元一个上下文)。这样做很有意义,但是我应该如何为在每个方法中创建和处理此上下文的类编写单元测试?

让我们看一个简化的虚构示例代码片段:

public class Resource : IResource {
    public Item GetItem(string name) {
        using(var context = new DbContext()) {
            return context.Items.FirstOrDefault(item => item.Name == name);
        }
    }
}

如果我想对资源进行单元测试,我想模拟 DbContext,所以它会为我返回一些假数据。

我通常的方法是使 DbContext 成为我的类的属性并像这样从外部注入它:

public class Resource : IResource {
    public DbContext Context { private get; set; }

    public Item GetItem(string name) {
        return this.Context.Items.FirstOrDefault(item => item.Name == name);
    }
}

这样,注入上下文的实例化类负责生命周期,我可以省略使用当然我可以注入一个模拟上下文。

现在考虑到,提供一个长期存在的上下文可能是一个坏主意,并且遵循每个工作单元一个上下文的原则,这个选项是不利的。

那么我有什么选择呢?一个想法是注入一个 ContextFactory,它可以像这样按需创建和处理上下文:

public class Resource : IResource {
    public DbContextFactory ContextFactory { private get; set; }

    public Item GetItem(string name) {
        using(var context = ContextFactory.CreateContext()) {
            return context.Items.FirstOrDefault(item => item.Name == name);
        }
    }
}

这是有道理的还是我会进入一个完全错误的方向?

4

2 回答 2

2

选项是使用方法注入:

   public Item GetItem(string name, DbContext context) {
        using(var context) {
            return context.Items.FirstOrDefault(item => item.Id == id);
        }
    }

Seemann 在他的 .Net 中的依赖注入一书中也使用这种方法来注入依赖关系,这种依赖关系可以随着调用而改变。

但我会使用ContextFactory.

于 2013-03-08T16:49:33.393 回答
1

我查看了 Mark Seemann 的书(由 Anton Sizikov 提到),他实际上也使用了工厂,称其为临时一次性的。它在某种程度上是一个泄漏抽象,因为工厂管理一次性依赖项的生命周期而不是 DI 容器。仍然比由于未处置的一次性用品或已处置的共享依赖项引起的异常而发生内存泄漏要好。

于 2013-06-14T07:43:22.040 回答