6

多年来,我一直在使用多种语言进行编程,并且喜欢认为我通常很擅长它。但是,我从未编写任何自动化测试:没有单元测试,没有 TDD,没有 BDD,什么都没有。

试图开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中的所有代码的理论价值。我可以看到像 RSpec 和 Mocha 这样的测试框架应该如何使设置和运行上述测试相当容易,我喜欢它们为编写测试提供的 DSL。

但我从未设法为我的代码的任何部分编写实际的单元测试。我写的东西似乎从来没有以实际有用的方式进行测试。

  • 在使用它们的上下文之外,函数似乎不是非常可调用的。我编写的许多函数都会进行 HTTP 请求调用、数据库查询或其他一些不易测试的调用。
  • 一些函数返回 HTML 字符串。我可以将 HTML 字符串与同一字符串的硬编码版本进行比较,但这似乎只会限制我更改该部分代码的能力。再加上在我的测试代码中有大量的 HTML 是一团糟。
  • 我可以将模拟/间谍对象传递给一个方法,并确保它们得到某些方法调用,但据我所知,这只是测试我正在“测试”的方法的实现细节。

我将如何开始正确的 BDD 测试?(我更喜欢使用 Mocha 和 Node.js 来做这件事,但是关于 BDD 的一般建议也很好。)

4

2 回答 2

3

看起来您要问的主要问题是“我如何编写可测试的代码”?

作为面向对象编程的粉丝,我知道我有偏见,但根据我的经验,测试以 OO 风格编写的代码要容易得多。这样做的原因是单元测试旨在测试系统的小型、隔离组件,而设计良好的面向对象代码(大部分)提供了这一点。

我同意函数通常与它们所处的上下文相关联,这使得它们难以测试。我在函数式编程方面没有太多经验,但我知道上下文经常以某种变量的形式传递,因此很难分离函数的关注点。

通过 OO 编程,我通过模拟执行实际网络请求以返回一组已知数据的对象,成功地测试了围绕 HTTP 请求、数据库查询等的对象。然后,您测试您的包装器对象是否以正确的方式处理该数据。您还可以测试失败和意外数据。另一种方法是设置您使用的本地服务器而不是普通端点,但这会给您的测试套件带来外部依赖,应尽可能避免。

在测试 HTML 时,由于视图层的高度可变性,很多人根本不这样做。然而,有些东西确实值得测试,但绝不是完整的 HTML 字符串——正如您所发现的,只是一个微小的变化就意味着整个测试都会中断。在这种情况下,您真正​​测试的是什么,代码库不同部分中的两个字符串是否相同?

最好的办法是将 HTML 字符串从您的函数/对象加载到 HTML 解析器库中,您通常可以使用 Xpath 或 CSS 选择器来检查具有特定类、ID 或其他属性的标签,并检查元素的数量符合某些要求的。Rspec 内置了这个(have_tag()方法),许多测试库也是如此。

您可能希望查看的其他内容是集成测试(例如 Capybara、Selenium)。这将使用 JavaScript 引擎加载您的 Web 应用程序,因此您可以检查 HTML 元素和 JavaScript 事件。

在整个模拟/存根的事情上,您通常只想对作为您正在测试的对象的依赖项的对象执行此操作。否则,您几乎可以操纵任何东西来断言为真!

至于测试资源,即使您不打算练习 TDD,我也建议您查看测试驱动开发书籍。主要原因是他们让你首先投入测试。这里有一些:

  1. 肯特贝克的书测试驱动开发:通过示例
  2. 使用 PHP 进行 TDD 的免费电子书,实用 PHP 测试
  3. 这个网站,单元测试的艺术
  4. Slideshare - 只需搜索单元测试或 BDD 并尽可能多地阅读!
  5. 大卫切利姆斯基等。al.:RSpec Book
于 2013-02-14T10:00:30.847 回答
0

TDD 或 BDD,没关系,它们是同构的,正如 Mocha 所证明的那样,它们只是可插入的前端。

我可以将模拟/间谍对象传递给一个方法,并确保它们得到某些方法调用,但据我所知,这只是测试我正在“测试”的方法的实现细节。

这正是单元测试的重点:你只测试你正在测试的代码,而不是更多。更多测试的问题在于,失败的测试通常不会准确地标记问题。单元测试的承诺是您可以在很大程度上避免调试。过于粗略的测试会使这一点无效。当然,平衡是必需的,任何有任何 UT 经验的人都会告诉你,很容易陷入我想要测试但没有注意到的陷阱,您的测试可能都是绿色的,实际代码不起作用。

于 2013-02-14T10:16:57.577 回答