繁体   English   中英

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

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM