我应该如何对使用Entity Framework实现的存储库方法进行单元测试?

时间:2014-04-05 14:23:43

标签: c# entity-framework unit-testing integration-testing moq

我的存储库层中有这样的方法:

public IEnumerable<User> GetActiveUsers()
{
    return dbContext.Users
           .Where(u => u.IsActive)
           .OrderBy(u => u.Name)
           .ToList();
}

我应该通过模拟DbContext来单元测试此方法,还是应该使用实际数据库对其进行测试?

我知道它不再是一个&#34;单位&#34;我在使用实际数据库时进行测试,但是我没有看到模拟DbContext以测试逻辑上很薄的存储库方法的价值,通常直接调用EF的方法。

如果我必须使用实际的数据库,是否有任何标准策略来填充数据库中的测试数据,以便测试独立运行并且不会改变数据库中的任何状态?

4 个答案:

答案 0 :(得分:3)

可能不是你想听到的,但你不想模仿DbContext。我知道它一直在做,在EF6中它甚至比以前更容易。还有更多的接口和虚拟方法可用于实现模拟对象。从技术上讲,这并不难。

这是重要的行为。

即使在你的小例子中,也有一个可能的问题。模拟DbSet会进行区分大小写的排序。连接的DbSet将从数据库接收已排序的数据,并且许多数据库归类恰好不区分大小写。因此,单元测试可以产生与集成测试不同的结果,即使在这个看似无关紧要的情况下也是如此。

内存和连接LINQ之间的差异为overwhelming。就个人而言,我只对涉及任何LINQ to Entities查询的任何内容进行集成测试。如果EF可以构建它,那么创建一个看起来不同的模拟对象图就太容易了。在我的服务方法中,我有时会编写相当复杂的查询,可能涉及Includes,可能故意省略null警卫,知道该语句被翻译成SQL,可能涉及一些延迟加载或依赖于关系修正。我必须要注意实体状态,上下文生命周期,在保存更改时启动的验证,并发......我只是不相信绿色测试,当它全部被嘲笑。

当然,还有足够的业务逻辑可以通过纯单元测试进行测试。一旦你可以假设正确的对象可用(因为你在集成测试中单独测试它),你可以模拟它们并在内存中单元测试它们的行为。

答案 1 :(得分:1)

另一方面:通过设置数据库并对其进行测试,您会获得哪些其他信息?

我只是简单地模拟DbContext,因为它最容易维护,因为基本上单元测试Entity-Framework对数据库的调用没有价值。

您想要测试的是您的LINQ查询是否从数据源返回数据。但是,这些LINQ查询被EF转换为SQL查询是你不会打扰的。

如果你真的想测试你的外部依赖关系,你可以将它视为一个额外的集成测试,但EF本身已经非常可靠,所以我怀疑这在任何方面都是有用的。

答案 2 :(得分:0)

如果将IEnumerable GetActiveUsers实现(并且它应该)作为接口,并且您发布的代码是实现该接口的具体类。然后,您通常会使用模拟框架来模拟您实现的接口并返回您设置的结果集。

正如Jeroen所提到的,您通常不需要对实体框架所做的事情进行单元测试。单元测试只测试你的逻辑,而不是其他库(这里的EF)逻辑。

答案 3 :(得分:0)

为DBContext编写Mock并执行LINQ查询时要记住的是,它们是作为LINQ to OBJECTs而不是LINQ to Entities运行的模拟上下文对象...(EF6)...

我个人会把时间花在测试行为上。 Julie Lerman有一个系列@ pluralsight和MSDN Mag在线,如果你必须测试如何测试dbContext。