2008-11-24 187 views
10

我理解需要测试具有逻辑的类(例如可以计算折扣的类),您可以在其中测试实际的类。我为什么要写一个假类和单元测试呢?

但是我刚开始为一个充当存储库的项目编写单元测试(从数据库获取对象)。我发现自己正在编写一个实现了ISomethingRepository接口的'假'存储库。它在内部使用Dictionary<Guid, Something>进行存储。它实现接口的Add(Something)GetById(Guid)方法。

我为什么要写这个?我正在编写的东西实际上会在软件部署时使用,对吧?我真的不明白这个练习的价值。

我也得到了使用模拟对象的建议,我可以提前设置以满足某些期望。这对我来说似乎更加毫无意义:当然,测试会成功,我已经嘲笑/伪装成功!而且我还不能确定实际的软件会连接到数据库时,它应该执行...

迷茫...

有人点我在正确的方向,以帮助我理解这?

谢谢!

+0

我对此表示满意,因为这经常令我感到厌烦。大多数快速的TDD倡导者倾向于意外陷入这种情况,最终导致测试场景/代码在现实中不会发生。 – FlySwat 2009-08-30 22:57:38

回答

13

你不是在测试你的模拟对象,而是在与它进行交互的其他类。所以你可以举个例子来测试一个控制器是否将一个保存方法调用转发到你的虚拟仓库。如果您正在“测试您的假物品”,则出现问题

+1

是的,这就是我的想法。那么我对测试我的数据访问代码有错误的想法。 例如:http://tinyurl.com/6qojvh – 2008-11-24 14:54:04

0

因为您想以简单的方式测试实现而不测试实际的具体类,所以您编写了称为Stub或Mock对象的“假”类。目的是通过仅测试接口(或抽象类)来简化测试。

在你的例子中,你正在测试的东西有一个词典。它可能会被数据库真实填满,或者有很多逻辑背后的逻辑。在你的“假”对象中,你可以通过使所有的数据保持不变来简化所有的事情。这样您只测试接口的行为,而不测试具体对象的构建方式。

+0

我明白了,但那有价值吗?我写了*假*并进行了测试。它不用于任何地方的生产代码。那么为什么写它并测试它呢? – 2008-11-24 14:51:20

+1

测试你的实现,而不必在你的路径中包含具体元素。您可以取出大量代码并专注于您的测试目的。我在我的帖子中的例子很好......数据库之一......你不需要有一个“真正的数据库”,你可以伪造它...... – 2008-11-24 15:00:59

2

模拟/存根对象的目的不是要测试,而不是你想测试单元的,它允许您测试单元,而无需其他类。

它基本上是这样的,你可以一次测试一个类,而不必测试他们也依赖的所有类。

+0

是的,这就是我的想法。因此,在通常使用存储库代码的“更高层”中,我可以注入一个模拟测试,以便它实际上不会连接到数据库,对吗? – 2008-11-24 14:53:07

+2

对那个 – 2008-11-24 14:53:32

1

谁在监视观察者?

有趣的是,如果模拟实现为角落案例抛出特定的异常,那么您知道使用或依赖IRepositorySomething的类可以处理在现实生活中抛出的异常。使用测试数据库无法轻松生成这些异常中的一些。

您不用单元测试来测试Mock对象,但可以使用它来测试依赖它的类。

3

不要测试模拟类。使用模拟类来测试生产类。

测试支持类的整点是要有一些可以预测其行为的东西。如果您需要测试测试支持类以预测其行为,则存在问题。

在您评论中链接的假数据库文章中,作者需要单元测试他的假数据库,因为它是他的产品(至少在文章的上下文中)。

编辑:更新的条款要更一致。

  • 模拟 - 以嘲弄的框架
  • 假创造 - 手动创建,实际上可能会发挥一些。
  • 测试支持 - 嘲笑,假货,存根,以及所有其他。不生产。
1

你不应该测试模拟类。

通常你会做的是:你为所测试的类与所有类进行交互的类创建模拟类。

假设您正在测试一个名为Bicycle的类,该类需要类Wheel,Saddle,HandleBar等的构造函数对象。

然后在课堂上你要测试自己的方法GetWeight这可能遍历每个部分并调用属性/方法权重,然后返回总数。

你做什么:

  • 你写一个模拟类简单地​​ 实现了权重比特
  • 然后你通过这些模拟类的自行车
  • 每个部分 (轮,马鞍等)
  • 测试GetWeight方法上的自行车类

这种方式,你在f在测试GetWeight的自行车类的方式,是独立于其他类OCUS(说,他们还没有实现,不确定性等)

1

而是自己写一个假类的,你可以使用一个工具(如犀牛或Typemock)来嘲笑它。这比自己写所有的嘲讽要容易得多。就像其他人说的那样,没有必要测试假代码,如果您使用该工具,则不需要代码。

1

实际上我发现了两个用于存储库实现测试的模拟类。

第一个是测试使用您提到的“ISomethingRepository”等价物的实现的服务。但是,我们的存储库实现是由工厂创建的。这意味着我们会针对“ISomethingRepository”编写测试,但不直接针对“MockSomethingRepository”。通过对接口进行测试,我们可以轻松断言,我们测试的代码覆盖率覆盖了接口的100%。代码评审提供了简单的验证,即新界面成员已经过测试即使开发人员针对工厂返回的模拟运行,构建服务器也具有不同的配置,用于测试工厂在每晚构建中返回的具体实现。它在测试覆盖率和本地性能方面提供了两全其美。

第二个使用是我很惊讶,没有人提到过的一个。我的团队负责中间层。我们的Web开发人员负责Web产品的前端。通过构建模拟存储库实现,在开始前端工作之前没有等待数据库建模和实施的人为障碍。可以编写视图来构建模拟,以提供最少量的“真实”数据以满足Web开发人员的期望。例如,可以提供数据以包含最小和最大长度的字符串数据,以验证这些数据不会中断它们的实现等。

由于我们使用的工厂连接到要返回的“ISomethingRepository”,因此我们有本地测试配置,构建测试配置,生产配置等。我们故意设法确保项目中没有任何团队由于另一个团队的实施时间而有不合理的等待时间。最大的等待时间仍然由开发团队提供,但我们能够以比前端开发更快的速度发掘我们的域对象,存储库和服务。

当然,YMMV。 ;-)

0

看一看下面这篇文章就是一个很好的解释:

http://msdn.microsoft.com/en-us/magazine/cc163358.aspx

基本上,如果你写一个假的对象,它原来是相当复杂的,有时值得单元测试假货以确保它按预期工作。

由于存储库可能很复杂,因此为它编写单元测试通常是有意义的。

0

通常不需要在数据访问层中运行传统的单元测试。 也许您可以使用单元测试框架的功能为您的数据访问类(即集成测试(=将数据访问层代码与数据库集成))编写整合样式单元测试。

例如,在Spring项目中,您可以使用Spring Testcontext在单元测试中启动Spring上下文,然后连接到真实数据库并测试查询返回正确结果。您可能需要自己的数据库进行单元测试,或者您可以将它们与开发人员数据库连接起来。

相关问题