嘲笑还是不嘲笑?

时间:2011-07-29 15:07:28

标签: unit-testing mocking

据我所知,在极限编程和单元测试中,测试必须由另一个开发人员在另一个开发测试方法之前完成(或者从相同的开发人员开始,但测试必须在方法实现之前编写)。

好的,看起来很好,我们只需要测试一个方法在给它一些参数时是否具有良好的行为。

但理论与实践之间的区别在于理论上没有,但在实践中却存在......

我第一次尝试测试时,由于物体之间的关系,我发现在某些情况下很难。我发现了嘲弄的做法,我发现它非常有用,但有些概念让我怀疑。

首先,模拟隐含的说:“你知道该方法是如何运行的,因为你必须知道它需要的其他对象......”。好吧,理论上我的朋友鲍勃写了测试,他只知道当我给它“john”字符串时该方法必须返回true ...这是我使用dao来访问数据库而不是使用内存中的哈希表...

我可怜的朋友鲍勃将如何编写测试?他会期待我的工作......

好吧,似乎不是纯粹的理论,而是无论如何。但是如果我查看很多模拟框架的文档,它们允许我测试一个方法的调用次数和顺序!哎哟......

但是如果我的朋友Bob必须测试这种方法以确保良好地使用依赖关系,那么该方法必须在测试之前编写,不是吗?

嗯......帮我的朋友鲍勃......

我们什么时候停止使用模拟机制(订单验证等)? 模拟机制有用吗? 理论,实践和模拟:什么是最佳平衡?

4 个答案:

答案 0 :(得分:7)

您的描述中似乎缺少的是将合同与实施分开的概念。在C#和Java中,我们有接口。在C ++中,只由纯虚函数组成的类可以填充此角色。这些并不是必需的,但有助于建立逻辑分离。因此,除了您似乎遇到的混乱之外,练习应该更像:鲍勃为一个特定的类/功能单元编写单元测试。在这样做时,他为其他类/单元定义了一个或多个接口(合同)来支持这个接口。他不需要立即编写这些文件,而是用模拟对象填充它们,以提供他的测试和被测系统所需的间接输入和输出。因此,一组单元测试的输出不仅仅是驱动单个单元开发的测试,而是 plus 需要由其他代码实现以支持当前正在开发的单元的合同。 / p>

答案 1 :(得分:4)

我不确定我是否理解你的问题。

使用模拟来验证对象之间的协作。例如,假设您有一个使用用户名和密码的Login()方法。现在假设您希望此方法记录失败的登录尝试。在单元测试中,您将创建一个模拟Logger对象,并在其上设置一个期望它将被调用。然后,您将依赖项将其注入您的登录类,并使用错误的用户名和密码调用您的Login方法以触发日志消息。

单元测试工具包中的另一个工具是存根。在您不测试协作时使用存根,而是伪造依赖关系以使您的类在测试中运行。

The Unit of Unit Testing 的作者Roy Osherove有一个关于模拟的好视频:TDD - Understanding Mock Objects

另外,我建议前往他的网站http://artofunittesting.com/,并在“单元测试视频”标题下观看右侧的免费视频。

答案 2 :(得分:1)

当您编写单元测试时,您正在针对预期结果和/或行为测试所测试类的结果和/或行为。

期望可以随着您开发类的时间而改变 - 新的需求可能会改变类的行为方式或调用特定方法的结果。它永远不会在石头和单元测试中进行,并且测试中的类一起发展。

最初,您可能会在非常精细的级别上开始只进行一些基本测试,然后逐渐演变成越来越多的测试,其中一些测试可能对您测试的类的实际实现非常特别(至少到目前为止)因为该类的可观察行为是关注的。)

在某种程度上,您可以针对正在测试的类的原始存根写出许多测试,这会产生预期的行为,但大多数还没有实现。然后你可以重构/开发“真实”这个类。

在我看来,尽管在开始时编写所有测试然后完全开发课程是一个梦想 - 根据我的经验,测试和测试中的课程一起发展。 也可以由同一个开发人员编写。

然后,我当然不是TDD纯粹主义者,只是试图以务实的方式充分利用单元测试。

答案 3 :(得分:0)

我不确定究竟是什么问题。所以我可能无法准确回答这个问题,但我会试一试。

假设您正在编写系统A,其中A需要从提供程序获取数据(简单地说是字符串),然后反转字符串并将其发送到另一个系统C.

B和C是为您提供的,它们实际上是接口,现实生活中的实现可能是BImpl和CImpl。

出于工作目的,您需要从系统B调用readData(),并从系统C调用sendData(String)。您的朋友Bob也应该知道,您不应该发送你得到它之前的数据。此外,如果你得到“abcd”,你应该发送“dcba”

看起来你和鲍勃都应该知道这一点,他写了测试,然后你编写代码......那里的问题在哪里?

当然现实生活更复杂,但您仍然可以通过单元测试的简单交互来对其进行建模。