TDD 由内而外:询问如何正确执行?

问题描述 投票:0回答:3

我正在尝试正确地进行 TDD!我读到的是 TDD Inside Out,而不是 Outside In。原因是我不知道我的层是如何预先编写的,所以我的想法是开始编写测试,让它失败,然后开始编写我的第一层。

在编写第一层时,我注意到我需要另一层,我们将其称为服务层。这就是我感到困惑的地方,我该怎么办?

我是否需要停止并创建一个失败的新测试,以便我可以使用 TDD 实现我的新服务层?完成后,我返回到原始层,我应该在这里创建服务层的模拟吗?或者使用我刚刚通过 TDD 创建的服务层?

这就是 TDD 对吗?因此,如果我在嘲笑事情,那么也许我的 TDD 并没有推动我的发展?但当然,如果我不模拟事情,这些从技术上讲不是单元测试,而是更多的集成测试?

如果我的单元测试(通过 TDD 编写)确实使用模拟,那么我需要进行一些其他类型的测试来测试每个单独层作为一个单元的集成?

集成测试还是端到端测试?

我认为我的问题基本上是当我需要引入新层时,我应该模拟这些层,我应该创建一个新测试来驱动这个新层的开发吗?

我希望有人能帮助我解决这个困惑!

谢谢

c# java unit-testing mocking tdd
3个回答
4
投票

随着经验的积累,你会变得更好。 但现在让我说一下。

首先,将 TDD 视为设计干净代码的工具(查看Bob 叔叔的干净代码 以获得更多见解。)。它绝不取代任何系统设计工作。这意味着您必须知道您想要类设计什么(至少粗略地),并且还必须定义这些类之间的接口。

其次,根据 Mike Cohn - 有效处理旧代码 - 第 2 章 进行的单元测试不会:

  1. 与数据库对话
  2. 通过网络进行交流
  3. 接触文件系统
  4. 要求您对运行环境执行特殊操作。

因此,您应该很好地满足单元测试的限制。

一般来说,您希望为每个组件(或类)编写单元测试。这意味着您为每个接口创建假类或模拟,例如对于每个服务层类。这意味着您必须知道每个调用所需的确切接口(方法参数和返回值)。 尝试在一个实例上尽可能走得更远,然后继续下一个实例。

如果您不确定您的设计应该是什么样子,请考虑构建一个未经测试的原型。只要有足够的代码,您就可以看到组件一起工作并帮助构建您的界面。然后画出设计草图,扔掉原型并使用 TDD 方法重新开始。


1
投票

以 TDD 风格进行开发时,您应该尽可能多地使用接口。

单元测试意味着您测试与大多数(最好是所有)其他代码隔离的每个单元。

所以在您的情况下:如果您当前处理的代码需要调用某个服务层。然后为新模块创建一个接口并模拟它们的正确行为(如果您想测试错误处理,则模拟预期的错误行为)。

...并将测试您的新服务层放在您的待办事项列表中;)

这样,当您开始处理此问题时,您可以将工作集中在当前单元上,并为您的服务层准备好接口。

如果您想测试各层如何协同工作,则需要某种集成测试。


0
投票

我更喜欢芝加哥学派的“Outside In”和“Inside Out”。它们并不相互排斥。选择适合工作的。

在大多数情况下,从“由外而内”开始,编写一些高级 TDD 测试(以 BDD 思维方式,但不要使用所谓的 BDD 框架)。当您意识到您的第一层不够时(即您找到尚未实现的协作者),请降低并为这些协作者编写 TDD 测试。因此,在一段时间内,您将有 2 项测试未通过,而不仅仅是 1 项。但是当你完成后,两层的测试都将开始工作。

那是芝加哥学校,所以所有课程都一起工作,你可以通过公共 API 来练习它们(通过测试行为,因为 BDD 是 TDD 的正确做法)。与之相反的是伦敦学派,在那里你可以嘲笑周围的事物。在伦敦风格中,你最终会得到测试模拟的测试,并且每次重构都是痛苦的。有些人确实承认这一点,甚至在伦敦学校,他们也会将模拟对象更改为真实对象(但这不是常见的方法)。

参见:

© www.soinside.com 2019 - 2024. All rights reserved.