3

我的一个朋友正在解释他们如何在他的工作场所使用 TDD 进行乒乓配对,他说他们采用“对抗性”方法。也就是说,当测试编写人员将键盘交给实施者时,实施者会尝试做最简单(有时是错误的事情)以使测试通过。

例如,如果他们正在测试 GetName() 方法并且测试检查“Sally”,则 GetName 方法的实现将是:

public string GetName(){
    return "Sally";
}

当然,这会(天真地)通过测试。

他解释说,这有助于消除检查特定固定值的幼稚测试,而不是测试组件的实际行为或预期状态。它还有助于推动创建更多测试并最终实现更好的设计和更少的错误。

听起来不错,但在与他的短暂对话中,通过一轮测试似乎比其他方式花费了更长的时间,我并不觉得获得了很多额外的价值。

您是否使用这种方法,如果是,您是否看到它得到了回报?

4

5 回答 5

2

它可能非常有效。

它迫使您更多地考虑您必须编写什么测试才能让其他程序员编写您需要的正确功能。

您经常通过键盘逐段构建代码

这可能非常累人且耗时,但我发现很少有我不得不回来修复任何像这样编写的代码中的错误

于 2008-10-03T21:32:11.310 回答
1

我用过这种方法。它不适用于所有配对;有些人只是天生抗拒,不会给它一个诚实的机会。但是,它可以帮助您正确执行 TDD 和 XP。您想尝试慢慢地将功能添加到您的代码库中。您不想编写需要大量代码才能满足的庞大的单体测试。你想要一堆简单的测试。您还需要确保定期在两对之间来回传递键盘,以便两对都接合。有了对抗性配对,你就可以做到这两点。简单的测试导致简单的实现,代码构建缓慢,整个过程都涉及到两个人。

于 2008-09-19T14:25:05.353 回答
0

我有时喜欢它——但不要一直使用这种风格。有时可以很好地改变节奏。我不认为我想一直使用这种风格。

我发现它对于初学者来说是一个有用的工具,可以介绍测试如何推动实现。

于 2008-09-19T21:33:58.987 回答
0

(首先,Adversarial TDD 应该很有趣。它应该是一个教学的机会。它不应该是人类统治仪式的机会。如果没有一点幽默的空间,那就离开团队。抱歉。在消极的环境中浪费生命是短暂的。)

这里的问题是命名错误的测试。如果测试看起来像这样:

foo = new Thing("Sally")
assertEquals("Sally", foo.getName())

然后我打赌它被命名为“ testGetNameReturnsNameField”。这是一个坏名字,但不是立即明显如此。此测试的正确名称是“ testGetNameReturnsSally”。这就是它的作用。任何其他名称都会使您产生虚假的安全感。所以这个测试的名字很糟糕。问题不在于代码。问题甚至不是测试。问题是测试的名称。

相反,如果测试人员将测试命名为“ testGetNameReturnsSally”,那么很明显这可能不是测试我们想要的。

因此,实施者有责任证明测试人员的错误选择。实现者的职责也是只写测试对他们的要求。

生产中出现如此多的错误不是因为代码做得比预期的少,而是因为它做得更多。是的,对所有预期的情况都有单元测试,但没有对代码所做的所有特殊边缘情况进行测试,因为程序员认为“我最好也这样做,我们可能需要那个”然后忘记了它。这就是为什么 TDD 比 test-after 工作得更好。这就是为什么我们在峰值之后丢弃代码。代码可能会做你想做的所有事情,但它可能会做一些你认为需要的事情,然后忘记了。

强迫测试作者测试他们真正想要的。仅编写代码以使测试通过,仅此而已。

RandomStringUtils 是你的朋友。

于 2019-03-12T20:10:45.657 回答
-1

这是基于团队的个性。每个团队的个性都是其成员的总和。您必须小心,不要以优越感来实践被动攻击性实施。一些开发人员对像这样的实现感到沮丧

return "Sally";

这种挫败感将导致一个不成功的团队。我很沮丧,没有看到它得到回报。我认为更好的方法是进行更多的口头交流,就如何更好地实施测试提出建议。

于 2008-09-19T14:37:52.777 回答