6

我正在尝试首先使用 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:考虑到内存 LINQ 和 SQL LINQ 之间的差异,如何测试 EntityFramework 代码?

很久以后的编辑:我已经找到了一个非常好的框架,可以完全满足我的需要。我写了一篇关于使用 Effort 进行单元测试的博客文章。另请注意,即将推出的 EF6 可能不需要所有这些,它承诺提供一些单元测试功能。

4

3 回答 3

8

为此,我们使用 SQLite 的内存数据库。它们的创建、查询和拆除速度极快,对整体测试速度几乎没有任何影响。一旦你建立了一个测试框架来创建数据库和注入数据,测试就可以快速编写。

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

这些测试是否构成集成测试?我不这么认为。他们仍然只测试代码的一个单元即生成 LINQ 查询的位。您正在测试两件事:1)查询返回正确的数据(但您可以使用内存中的集合来检查这一点,如您所说),以及2)实体框架可以将查询转换为有效的 SQL。测试后者的唯一真正方法是在真实的实体框架上触发查询,但使用存根数据库。

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

于 2012-08-30T12:59:14.763 回答
1

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

易于测试但在某些重要情况下实际上并不代表实时系统的内存提供程序有什么好处?

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

于 2012-08-30T12:51:17.423 回答
0

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

这将使您对测试代码中发生的事情有很大的控制权。(这里简短介绍。)

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

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

这里或通过 NuGet也有一个免费的“精简版”版本。

于 2012-08-30T16:00:05.247 回答