你如何在一个非平凡的应用程序中进行TDD?

时间:2008-10-17 07:49:35

标签: tdd agile

我读过很多关于TDD主题的书籍和网站,它们都很有意义,特别是Kent Beck的书。然而,当我尝试自己做TDD时,我发现自己正盯着键盘,想知道如何开始。你使用过程吗?你的思考过程是什么?你如何确定你的第一次测试?

关于这个主题的大部分书籍都很好地描述了TDD是什么,而不是如何在现实世界的非平凡应用程序中练习 TDD。你是怎么做TDD的?

8 个答案:

答案 0 :(得分:5)

实际上,这比你想象的要容易。您只需在每个班级使用TDD。应该测试您在课堂上的每个公共方法的所有可能结果。因此,您看到的“概念证明”TDD示例也可用于具有数百个类的相对较大的应用程序。

您可以使用的另一种TDD策略是通过封装主应用程序行为来模拟应用程序测试运行。例如,我编写了一个框架(在C ++中,但这应该适用于任何OO语言),它代表一个应用程序。有初始化,主runloop和关闭的抽象类。所以我的main()方法看起来像这样:

int main(int argc, char *argv[]) {
  int result = 0;

  myApp &mw = getApp(); // Singleton method to return main app instance
  if(mw.initialize(argc, argv) == kErrorNone) {
    result = mw.run();
  }

  mw.shutdown();
  return(result);
}

这样做的好处是双重的。首先,可以将所有主要应用程序功能编译到静态库中,然后将其与测试套件和此main.cpp存根文件链接。其次,这意味着我可以通过为argc& amp;创建数组来模拟主应用程序的整个“运行”。 argv [],然后模拟main()中会发生什么。我们使用这个过程来测试许多真实的功能,以确保应用程序在给定某个真实世界的输入数据和命令行参数的情况下生成它应该做的事情。

现在,您可能想知道如何为具有真实GUI,基于Web的界面或其他任何应用程序的应用程序进行更改。对此,我只想说使用模型来测试程序的这些方面。

但简而言之,我的建议归结为:将测试用例分解到最小的水平,然后开始向上看。最终,测试套件将把它们全部放在一起,最终你将获得合理水平的自动测试覆盖率。

答案 1 :(得分:4)

我曾经遇到过同样的问题。我曾经通过启动一个窗口设计器为我想要实现的第一个功能创建UI来开始大多数开发。由于UI是测试这种工作方式最困难的事情之一,因此不能很好地转换为TDD。

我发现Presenter First上的原子对象文章非常有用。我仍然首先想象我想要实现的用户操作(如果你有一个很好的开始使用的用例)并且使用MVP或MVC-ish模型我开始为第一个屏幕的演示者编写测试。通过模拟视图直到演示者工作,我可以通过这种方式快速入门。 http://www.atomicobject.com/pages/Presenter+First这里有关于这种方式工作的更多信息。

如果您正在使用您不了解或有许多未知的语言或框架开始项目,您可以先开始执行加标。我经常为我的尖峰编写单元测试,但只是为了运行我正在加速的代码。执行加标可以为您提供有关如何启动实际项目的一些信息。当你开始真正的项目时,不要忘记丢掉你的尖峰

答案 2 :(得分:3)

我从思考需求开始。

foreach UseCase

  1. 分析UseCase
  2. 想想未来的课程
  3. 记下测试用例
  4. 写测试
  5. 测试和实施课程(如果我在第4点错过了某些课程,有时会添加新测试)。
  6. 就是这样。这很简单,但我认为这很费时间。我喜欢它,但我坚持下去。 :)

    如果我有更多时间,我会尝试在Enterprise Architect中建模一些顺序图。

答案 3 :(得分:1)

我同意引导这个过程特别困难。

我通常会尝试将第一组测试视为电影脚本,也许只是影片中的第一个场景。

  

Actor1告诉Actor2世界是   陷入困境,Actor2交出一个   包,Actor1解压缩包,   等

这显然是一个奇怪的例子,但我经常发现可视化交互是克服初始驼峰的好方法。还有其他类似的技术(用户故事,RRC卡等)适用于大型团体,但听起来你是独立的,可能不需要额外的开销。

另外,我确信你要做的最后一件事是阅读另一本书,但是MockObjects.com的人们在早期选秀阶段有一本书,目前标题为Growing Object-Oriented Software, Guided by Tests。目前正在审查的章节可以让您进一步了解如何启动TDD并在整个过程中继续进行。

答案 4 :(得分:1)

问题是你正在看你的键盘,想知道你需要写什么测试。

相反,想一想你要编写的代码,然后找到该代码的第一个小部分,然后试着想一下会强制你编写那么一小段代码的测试。

一开始,它有助于使用非常小块。即使在一天的过程中,你也会在更大的块中工作。但是每当你遇到困难时,只要想想你接下来要编写的最小代码,然后为它编写测试。

答案 5 :(得分:0)

我认为你不应该从TDD开始。说真的,你的规格在哪里?您是否同意系统的一般/粗略整体设计,可能适合您的应用?我知道TDD和敏捷不鼓励Big Design Up-Front,但这并不意味着在开始实施该设计之前,你不应该首先进行Design Up-Front。

答案 6 :(得分:0)

有时您不知道如何进行TDD,因为您的代码不是“测试友好”(易于测试)。

由于一些良好的实践,您的课程可以更容易单独测试,以实现真正的单元测试。

我最近遇到了一位Google员工blog,其中介绍了如何设计类和方法,以便更容易测试。

Here is one of his recent talks我推荐。

他坚持认为你必须通过使用依赖注入模式将业务逻辑与对象创建代码分开(即避免将逻辑与'new'运算符混合)。他还解释了Demeter法对可测试代码的重要性。他主要关注Java代码(和Guice),但他的原则应该适用于任何语言。

答案 7 :(得分:0)

最简单的方法是从没有依赖项的类开始,这是一个由其他类使用的类,但不使用另一个类。那么你应该选择一个测试,问自己“我怎么知道这个类(这个方法)是否正确实现了?”。

然后你可以编写第一个测试来在你的对象未初始化时询问你的对象,它可以返回NULL,或者抛出异常。然后你可以初始化(可能只是部分)你的对象,并测试它返回一些有价值的东西。然后,您可以使用另一个初始化值添加测试 - 应该以相同的方式运行。那时,我通常测试错误条件 - 例如尝试使用无效值初始化对象。

完成该方法后,转到同一个类的另一个方法,直到完成整个类。

然后你可以选择另一个类 - 另一个独立的类,或者使用你实现的第一个类的类。

如果你选择一个依赖于你的第一堂课的课程,我认为让你的测试环境 - 或者你的第二课 - 实例化第一堂课是可以接受的,因为它已经过全面测试。当关于类的一个测试失败时,您应该能够确定问题所在的类。

如果你在第一堂课中发现问题,或者询问它是否会在某些特定条件下表现正常,那么就写一个新的测试。

如果爬上依赖关系,您认为您正在编写的测试跨越多个类被认定为单元测试,那么您可以使用模拟对象将类与系统的其余部分隔离开来。


如果您已经有了自己的设计 - 正如您在Jon LimJap的回答中所说的那样,那么您就不会使用纯TDD,因为TDD是关于使用单元测试让您的设计出现。

话虽如此,并非所有商店都允许严格的TDD,并且你手头有设计,所以让我们使用它并做TDD - 尽管说测试优先编程会更好但是那不是重点,因为那是我是如何开始TDD的。