TDD - 初学者问题和绊脚石

Nou*_*him 23 python tdd testdrivendesign

虽然我已经为大部分代码编写了单元测试,但我最近才拿到了Kent Beck的TDD副本.我一直对我做出的某些设计决定表示遗憾,因为它们阻止了应用程序的"可测试性".我读完了这本书,虽然其中一些看起来很陌生,但我觉得我可以管理它并决定在我当前的项目上试用它,这个基本上是一个客户端/服务器系统,两个部分通过它进行通信.USB.一个在小工具上,另一个在主机上.该应用程序是在Python中.

我开始了,很快就纠缠在一堆重写和小测试中,我后来认为它没有真正测试任何东西.我扔掉了大部分,现在有一个工作应用程序,测试已经凝结成只有2.

根据我的经验,我有几个问题,我想问一下.我从新到TDD获得了一些信息:是否有示例应用程序进行测试以显示如何进行TDD?但有一些我想要回答/讨论的具体问题.

  1. Kent Beck使用他添加的列表并从中指出开发过程.你怎么做这样的清单?我最初有一些项目,如"服务器应该启动","服务器应该中止,如果渠道不可用"等但他们混合,最后现在,它只是"客户端应该能够连接到服务器"(其中包含服务器启动等).
  2. 你如何处理重写?我最初选择了基于命名管道的半双工系统,这样我就可以在自己的机器上开发应用程序逻辑,然后再添加USB通信部分.它们被移动成为基于套接字的东西,然后从使用原始套接字转移到使用Python SocketServer模块.每当事情发生变化时,我发现我必须重写相当多的部分测试,这很烦人.我认为在我的开发过程中测试将是一个有点不变的指导.他们感觉更像是要处理的代码.
  3. 我需要一个客户端和一个服务器通过该通道进行通信以测试任何一方.我可以嘲笑其中一方来测试另一方但是整个频道都不会被测试,我担心我会想念它.这减少了整个红/绿/重构节奏.这只是缺乏经验还是我做错了什么?
  4. "伪造它直到你制造它"给我留下了许多混乱的代码,我后来花了很多时间来重构和清理.这是事情的运作方式吗?
  5. 在会话结束时,我现在让我的客户端和服务器运行大约3或4个单元测试.我花了大约一个星期的时间来做这件事.如果我在代码方式之后使用单元测试,我想我可以在一天内完成它.我没有看到收益.

我正在寻找那些使用这种方法完全(或几乎完全)实施大型非平凡项目的人的意见和建议.我已经运行的东西想要添加一个新功能对我来说是有意义的,但是从头做起它似乎很烦人而且不值得努力.

PS:如果这应该是社区wiki,请告诉我,我会这样标记.

更新0:所有答案都同样有用.我选了一个我做的,因为它最能引起我的经历.

更新1:实践练习练习!

Mat*_*ias 10

作为初步评论,TDD采取了实践.当我回顾我开始TDD时所写的测试时,我看到很多问题,就像我看几年前编写的代码一样.继续这样做,就像你开始认识到糟糕的好代码一样,你的测试会发生同样的事情 - 耐心等待.

你怎么做这样的清单?我最初有一些项目,如"服务器应该启动","服务器应该中止,如果渠道不可用"等但他们混合,最后现在,它只是"客户端应该能够连接到服务器"

"列表"可以是非正式的(在Beck的书中就是这种情况),但是当你开始将项目变成测试时,尝试将语句写成"[当发生这种情况时]"然后[这种情况应该是真的那个"格式.这将迫使您更多地考虑您正在验证的内容,如何验证它以及直接转换为测试 - 或者如果不能,它应该为您提供关于缺少哪个功能的线索.想想用例/场景.例如"服务器应该启动"不清楚,因为没有人正在启动一个动作.

每当事情发生变化时,我发现我必须重写相当多的部分测试,这很烦人.我认为在我的开发过程中测试将是一个有点不变的指导.他们感觉更像是要处理的代码.

首先,是的,测试是更多的代码,需要维护 - 编写可维护的测试需要练习.我同意S. Lott,如果你需要经常更改你的测试,你可能会测试"太深".理想情况下,您希望在公共接口级别进行测试,这种级别不太可能发生变化,而不是在可能发展的实现细节级别进行测试.但是部分练习是关于设计,所以你应该期望得到一些错误,并且还必须移动/重构你的测试.

我可以嘲笑其中一方来测试另一方但是整个频道都不会被测试,我担心我会想念它.

对那个不完全确定.从它的声音来看,使用模拟是正确的想法:采取一方,模拟另一方,并检查每一方是否正常工作,假设另一方正确实施.整个系统的测试是集成测试,您也希望这样做,但通常不是TDD过程的一部分.

"伪造它直到你制造它"给我留下了许多混乱的代码,我后来花了很多时间来重构和清理.这是事情的运作方式吗?

在进行TDD时,您应该花费大量时间进行重构.另一方面,当你伪造它时,它是暂时的,你的下一步应该是取消伪造它.通常你不应该通过多次测试,因为你假装它 - 你应该一次专注于一件,并尽快重构它.

如果我在代码方式之后使用单元测试,我想我可以在一天内完成它.我没有看到收益.

再次,它需要练习,你应该随着时间的推移变得更快.此外,有时TDD比其他TDD更有成效,我发现在某些情况下,当我确切地知道我想要编写的代码时,编写代码的大部分代码然后编写测试会更快.
除了贝克,我喜欢的一本书是Roy Osherove的单元测试艺术.它不是TDD书籍,它是面向.Net的,但你可能想要看一看:很好的部分是关于如何编写可维护的测试,测试质量和相关问题.我发现这本书在经过书面测试后很有共鸣,有时也很难做到......
所以我的建议是,不要过快地扔掉毛巾,并给它一些时间.您可能还想更轻松地尝试一下 - 测试服务器通信相关的东西听起来不是最容易开始的项目!


S.L*_*ott 8

  1. Kent Beck使用了一个列表......最后,它就像"客户端应该能够连接到服务器"(包含服务器启动等).

通常是不好的做法.

对架构的每个单独层进行单独测试是好的.

综合测试往往会掩盖架构问题.

但是,只测试公共功能.不是每个功能.

并且不要投入大量时间来优化测试.测试中的冗余不会像在工作应用程序中那样受到伤害.如果事情发生变化并且一个测试工作,但另一个测试中断,那么也许你可以重构你的测试.不是之前.

2.你如何处理重写?......我发现我必须重写大部分测试.

你的测试结果太低了.测试最外层的公共可见界面.那应该是不变的部分.

是的,重大的架构变化意味着重大的测试变更

测试代码是您如何证明工作的方式.它几乎与应用程序本身一样重要.是的,这是更多的代码.是的,你必须管理它.

3.我需要一个客户端和一个服务器通过该通道进行通信以测试任何一方.我可以嘲笑其中一方来测试另一方但是整个通道都不会被测试......

有单元测试.随着嘲笑.

有集成测试,测试整个事情.

不要混淆他们.

您可以使用单元测试工具进行集成测试,但它们是不同的东西.

你需要做两件事.

4."伪造它直到你制造它"给我留下了许多凌乱的代码,后来我花了很多时间来重构和清理.这是事情的运作方式吗?

是.这正是它的工作原理.从长远来看,有些人发现这比试图预先做好所有设计的大脑更有效.有些人不喜欢这样,想要预先做好所有设计; 如果你愿意的话,你可以自由地做很多设计.

我发现重构是一件好事,前面的设计太难了.也许是因为我已经编写了近40年的时间,而且我的大脑已经疲惫不堪.

我没有看到收益.

所有真正的天才都发现测试会减慢它们的速度.

在我们有一套完整的测试证明它可行之前,我们其他人无法确定我们的代码是否有效.

如果您不需要证明代码有效,则不需要测试.