如何单元测试实体框架?

时间:2012-08-30 12:39:08

标签: c# linq unit-testing ef-code-first

我正在尝试首先使用EntityFramework代码测试我的代码。为了使其可测试并允许隔离测试,我创建了一个我的DbContext实现的接口。我没有测试DbContext类 - 我将假设EF代码按预期工作。

现在,请考虑以下方法:

public IEnumerable<User> GetOddId()
{
    return context_.Users.Where((u, i) => i % 2 == 1).AsEnumerable();
}

此方法将通过我的模拟FakeDbSet传递(因为它将使用内存中的LINQ提供程序),而在使用EF / LINQ to SQL驱动程序时,它会因异常而失败。

你会保持原样并希望人们知道不要写这样的问题吗?你会放弃隔离测试并测试实际的数据库吗?

带有DataMigrations的LocalDb(可能带有适当的种子)是否有助于对实际数据库进行测试?

请证明答案是合理的。

TLDR:如何测试EntityFramework代码,考虑内存LINQ和SQL LINQ之间的差异?

很久以后编辑:我已经找到了一个非常好的框架,完全符合我的需要。我写了一篇关于unit testing with Effort的博文。另请注意,即将推出的EF6可能不需要这一切,它承诺提供一些单元测试功能。

3 个答案:

答案 0 :(得分:8)

为此,我们使用SQLite的内存数据库。它们可以非常快速地创建,查询和拆除,并且几乎不会对整体测试速度产生任何影响。一旦你为自己设置了一个测试框架来创建数据库并注入数据,就可以快速编写测试。

当然,SQLite是一个比大多数人简单得多的数据库,因此复杂的查询可能无法转换为其SQL版本,但是为了测试90%的情况,它运行良好。

这些测试是否构成集成测试?我不这么认为。他们仍然只测试一个你的代码单元,即生成LINQ查询的位。您正在测试两件事: 1)查询返回正确的数据(但您可以使用内容集合检查此内容),并且 2)可以通过Entity Framework将查询转换为有效的SQL。测试后者的唯一真正方法是在真实的实体框架中激活查询,但使用 stubbed 数据库。

虽然您可能认为真正的单元测试应该仅测试代码的输出(即解析并检查已生成的表达式树),以及更难编写,但它并不能真正证明任何东西。例如,如果您修改代码以生成内部联接而不是子查询,您是否希望测试中断?只有当它返回不同的结果时,我才会想到。

答案 1 :(得分:1)

在我工作的地方,我们有一个dev / beta / production SQL服务器。有时我们会在对实际数据库执行测试之前,针对beta和种子测试数据(例如在测试特定选择之前插入等)创建测试。人们会区分单元测试和集成测试,但它至少让我们测试我们的逻辑,这比仅仅交叉手指更好,希望在数据访问层最好。

内存提供商有什么用,它很容易测试但在某些重要情况下实际上并不代表实时系统?

编辑:我们不使用EF,顺便说一句......

答案 2 :(得分:0)

您可能希望使用像Telerik的JustMock这样的模拟框架(或从许多其他人中选择)。

这将使您可以控制测试代码中发生的事情。 (简介here。)

您可以“模拟”查询并返回预定义的对象集合,而不是对真实数据库实施查询。

例如,您可以创建多个调用GetOddId()方法的单元测试,并定义涵盖所有测试用例的不同返回集合(空列表,正确内容,错误内容,抛出异常)无论如何......)。

还有一个免费的'Lite'版本here或通过NuGet。