![](/img/trans.png)
[英]How do I properly unit test a repository-pattern method, that has coupling to Entity Framework / DbContext?
[英]How should I unit test a repository method implemented with Entity Framework?
我的存储库层中有一个像这样的方法:
public IEnumerable<User> GetActiveUsers()
{
return dbContext.Users
.Where(u => u.IsActive)
.OrderBy(u => u.Name)
.ToList();
}
我应该通过DbContext
对该方法进行单元测试还是应该在实际的数据库中对其进行测试?
我知道当我使用实际的数据库时,它不再是“单元”测试,但是我看不到DbContext
来测试逻辑上比较薄的存储库方法的价值,通常只直接调用EF的方法。
而且,如果我必须使用实际的数据库,是否有任何标准策略来填充数据库中的测试数据,以便测试独立运行并且不会更改数据库中的任何状态?
可能不是您想听到的,但您不想模拟DbContext
。 我知道它已经无休止地完成了,在EF6中甚至比以前更容易实现。 还有更多接口和虚拟方法可用于实现模拟对象。 从技术上讲,这并不难。
重要的是行为。
即使在您的小示例中,也可能存在问题。 模拟DbSet
将执行区分大小写的排序。 连接的DbSet
将从数据库接收排序的数据,并且许多数据库排序DbSet
区分大小写。 因此,即使在这种看似微不足道的情况下,单元测试也可能产生与集成测试不同的结果。
内存和连接的LINQ之间的差异是巨大的 。 就个人而言,我只对涉及任何LINQ to Entities查询的任何内容进行集成测试。 创建一个模拟对象图太容易了,如果EF会建立一个模拟对象图的话,它看起来会有所不同。 在我的服务方法中,有时我会编写非常复杂的查询,可能涉及Includes
,或者故意省略null
保护,因为知道该语句已转换为SQL,可能涉及一些延迟加载或依赖关系修正。 我必须知道实体状态,上下文寿命,保存更改时会生效的验证,并发...我只是不相信绿色测试在全部被嘲笑后才会生效。
当然,还有足够的业务逻辑可以用纯单元测试进行测试。 一旦可以假设正确的对象可用(因为您在集成测试中分别进行测试)就可以模拟它们并在内存中对它们的行为进行单元测试。
另一方面:通过建立数据库并对此进行测试,您还将获得哪些其他信息?
我会简单地模拟DbContext
因为它最容易维护,并且因为对数据库进行实体框架的调用实质上没有单元测试的价值。
您要测试的是LINQ查询是否从数据源返回数据。 但是,您不会理会那些EF会将那些LINQ查询转换为SQL查询。
如果您确实想测试您的外部依赖关系,则可以将其视为附加的集成测试,但是EF本身已经非常可靠,因此我怀疑这在任何方面都将是有用的。
如果IEnumerable GetActiveUsers被实现(并且应该作为接口),并且您发布的代码是实现该接口的具体类。 然后,通常将使用模拟框架模拟您实现的接口并返回您设置的结果集。
如Jeroen所述,您通常不需要对实体框架的功能进行单元测试。 单元测试仅测试您的逻辑,而不测试其他库(此处为EF)的逻辑。
为您的DBContext编写模拟并执行LINQ查询时要记住的一点是,它们以LINQ to OBJECTs而不是LINQ to Entities ...(EF6)的形式在模拟上下文对象上运行。
我个人将花费您的时间来测试行为。 朱莉·勒曼(Julie Lerman)在线上有一系列@pluralsight和MSDN Mag,内容涉及如何在必要时测试dbContext。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.