可读的测试名称与minitest

时间:2014-06-10 19:42:21

标签: ruby-on-rails automated-tests minitest

我在新的Rails项目中使用MiniTest,这是我第一次真正进行测试。当测试失败时,消息看起来像这样

  1) Failure:
Category::when created#test_0002_must have a unique name [/home/caleb/workspace/buzz/test/models/category_test.rb:10]:
Expected: true
  Actual: false

您可以将#test_0002_更改为另一个字符串以使错误更具可读性吗?我知道这是一个小问题,但这似乎应该得到支持。

# Example test
require 'test_helper'

describe Category do
  describe 'when created' do
    unique = false
    it 'must not have a unique name' do
      unique.must_equal false
    end
    it 'must have a unique name' do
      unique.must_equal true
    end
  end
end

1 个答案:

答案 0 :(得分:4)

嗯,这里有很多东西需要报道,所以请耐心等待。

首先,测试名称是可读的。而且它们是100%准确的。当您使用规范DSL时,您仍然在创建测试类和测试方法。在您的情况下,您的课程为Category::when created,您的考试方法为test_0002_must have a unique name。它们之间的#是一个非常常见的Ruby习语,用于类的实例方法,这是您的测试方法。当您使用classdef时,您无法创建包含空格的类或方法,但是当您以编程方式创建它们时,您可以。运行代码时,Ruby不关心它们是否有空格。

其次,我们可以影响测试类和方法的显示。该文本来自对Minitest::Test#to_s的调用。这是看起来像:

def to_s # :nodoc:
  return location if passed? and not skipped?

  failures.map { |failure|
    "#{failure.result_label}:\n#{self.location}:\n#{failure.message}\n"
  }.join "\n"
end

当测试失败时,将返回更多信息,包括失败的原因。但我们关心的是location。这是看起来像:

def location
  loc = " [#{self.failure.location}]" unless passed? or error?
  "#{self.class}##{self.name}#{loc}"
end

啊,更好。在最后一行,您可以清楚地看到它正在打印类和方法名称。如果测试失败,则该位置还包括定义方法的文件名。让我们打破这些值,使它们不是内联的:

def location
  loc = " [#{self.failure.location}]" unless passed? or error?
  test_class = self.class
  test_name = self.name
  "#{test_class}##{test_name}#{loc}"
end

好的,更清楚一点。首先是测试类,然后是#,然后是测试名称,然后是测试未通过的位置。现在我们已经将它们分解了,我们可以稍微修改它们。让我们使用/来分隔类名称空间和测试方法:

def location
  loc = " [#{self.failure.location}]" unless passed? or error?
  test_class = self.class.to_s.gsub "::", " / "
  test_name = self.name
  "#{test_class} / #{test_name}#{loc}"
end

大。现在让我们从测试方法的开头删除test_0002_。这是由规范DSL添加的,通过删除它我们可以使它匹配传递给it块的字符串:

def location
  loc = " [#{self.failure.location}]" unless passed? or error?
  test_class = self.class.to_s.gsub "::", " / "
  test_name = self.name.to_s.gsub /\Atest_\d{4,}_/, ""
  "#{test_class} / #{test_name}#{loc}"
end

现在,您的测试输出将如下所示:

  1) Failure:
Category / when created / must have a unique name [/home/caleb/workspace/buzz/test/models/category_test.rb:10]:
Expected: true
  Actual: false

Minitest与任何其他Ruby库没什么不同。规范DSL只是一个用于创建测试类和方法的瘦包装器。您可以改变测试对象的行为,使其按照您希望的方式工作。

TL; DR 将以下内容添加到test/test_helper.rb文件中:

class Minitest::Test
  def location
    loc = " [#{self.failure.location}]" unless passed? or error?
    test_class = self.class.to_s.gsub "::", " / "
    test_name = self.name.to_s.gsub /\Atest_\d{4,}_/, ""
    "#{test_class} / #{test_name}#{loc}"
  end
end