4

我正在构建一个 Ruby 命令行程序,并使用 Cucumber 和 Aruba 对其进行测试。Aruba 包含一些非常方便的匹配器,因此我可以使用文件中的几行来测试输出.feature

When I run `myprogram`
Then it should pass with:
  """
  my program output
  """

问题是我的程序可能包含几十行甚至上百行的输出;将所有这些都放在.feature文件中会使阅读和导航变得更加困难(并且有点令人讨厌)。在这种情况下测试输出的推荐方法是什么?

4

4 回答 4

7

简短的回答是:你不应该那样做。

Cucumber 测试应该是面向用户的和可读的。它们描述了特征。用户不会关心错误输出是否逐字节匹配某个已知值。

你需要问自己:我在测试什么?答案是错误信息吗?可能不是。您正在测试应用程序中的某些功能。如果您真的想确保它失败,那么您在 Cucumber 场景中想要的是以下行:

Then the exit status should not be 0

这假设脚本遵循标准约定,即非零退出状态表示错误。

如果您的场景要求输出中有特定消息,您可以添加它:

Then it should fail with
"""
Some error message
"""

但这不必是整个输出,只是部分匹配。(请注意,在 aruba 中定义了一个“它应该完全失败:”,但我不建议使用它。)

编辑:您已将示例更改为测试通过而不是失败,但我的基本建议是相同的:

  1. 将输出的细节与场景的逻辑分开。使用评论中的示例,如果您有一个测试确认您可以输出单个用户生成的评论,并且另一个测试确认您输出了正确的 100 条评论,那么就足够了,您不需要 100 Cucumber 场景中评论的输出价值。
  2. 保持从用户的角度编写 Cucumber 场景。每个场景都应该测试对用户很重要的东西。当用户不关心时,尝试通过删除从实现中泄漏的任何内容来使它们最小化。
  3. 使用测试部分匹配的内置 Aruba 构造来实现此目的。在输出中寻找关键词或短语。Cucumber 测试不仅更容易阅读,而且更健壮,不受无关输出变化的影响。
于 2012-12-11T23:20:20.297 回答
2

要测试您的程序,您有 2 个选项:

  1. 仅检查消息的相关部分(您实际希望通过此测试检查的内容)。Aruba 为其内置了 stepdef,因此非常简单

  2. 检查完整消息。如果消息很短,您可以使用 Aruba 的内置 stepdef。但是,如果消息很长,您可能希望将其放在单独的文件中。由于 Aruba 不包含此类方法,因此您应该自己编写此 stepdef。

它可能看起来像:

# Require aruba/api before that
Then /^it should (pass|fail) with message from file "(.*)"$/ do |pass_fail, filename|
  exact_output = File.read(filename)
  Aruba::API::assert_exit_status_and_output(pass_fail == "pass", exact_output, true)
end

如果你想写很多测试并且很多消息是相似的,你最终可能会得到很多WET消息。如果发生更改,断言完整消息将使支持测试变得更加困难。

因此,您可能希望使用某种模板引擎来断言这些消息以进行 DRYer 测试。

您可以以不同的方式设计测试。
如果您只使用第一种方法,那么您的测试可能不会发现一些回归错误,因为它们不会测试所有内容。如果您将使用第二种方法,如果消息之间有很多重复,那么支持它们可能会更加困难。

因此,这两个选项之间需要权衡取舍。通常您使用方法 1 构建一些测试,使用方法 2 构建另一个测试。您应该考虑在您的情况下什么会更好。我不知道任何黄金法则。

于 2012-12-11T22:09:05.960 回答
0

在一个应用程序中,数百个输出并不奇怪。是的,您需要使它们易于阅读。如果你不能在 Cucumber 特性文件中做到这一点,恐怕没有更好的地方可以替换。毕竟 Cucumber 完全是简单的英语,并且可以作为实时文档。

您所需要的只是组织它们。如果您忽略了它们,这里有一些基本提示。

  1. 编写每个.feature文件仅涵盖一个主题的特定功能。虽然我知道你提到When I run my program的是为了演示目的,但如此广泛的话题是不可接受的。

  2. .feature文件放入features/文件夹。并且,如有必要,进一步将它们拆分为子文件夹,例如features/user/user_login.feature.

  3. 在一个场景中使用Scenario OutlineExamples组织类似的输出。这些示例将有行来清楚地表示它们中的每一个。

希望这些帮助。

于 2012-12-11T05:54:51.023 回答
0

我会推荐以下内容:

When I run `my_app`
Then the exit status should not be 0
And the output should contain:
"""
some output
"""

这样,只要您的程序输出“一些输出”,测试就通过了,但额外的输出会被忽略,您的测试不需要所有输出。

如果您想在一个步骤中断言所有这些,只需自己制作,尽管我认为这更清楚。

于 2012-12-15T14:49:36.730 回答