Minitest规格自定义匹配器

时间:2012-09-04 16:04:05

标签: ruby minitest

我的考试中有一句话:

page.has_reply?("my reply").must_equal true

并使其更具可读性我想使用自定义匹配器:

page.must_have_reply "my reply"

基于https://github.com/zenspider/minitest-matchers的文档,我希望我需要编写一个看起来像这样的匹配器:

def have_reply(text)
  subject.has_css?('.comment_body', :text => text)
end
MiniTest::Unit::TestCase.register_matcher :have_reply, :have_reply

问题在于我无法看到如何获得对主题的引用(即页面对象)。文档说“注意主题必须是断言中的第一个参数”,但这并没有真正帮助。

2 个答案:

答案 0 :(得分:6)

有一个小例子,您可以创建一个应该响应方法集matches?failure_message_for_shouldfailure_message_for_should_not的类。 在matches?方法中,您可以获得对主题的引用。

class MyMatcher
  def initialize(text)
    @text = text
  end

  def matches? subject
    subject =~ /^#{@text}.*/
  end

  def failure_message_for_should
    "expected to start with #{@text}"
  end

  def failure_message_for_should_not
    "expected not to start with #{@text}"
  end
end

def start_with(text)
  MyMatcher.new(text)
end
MiniTest::Unit::TestCase.register_matcher :start_with, :start_with

describe 'something' do
  it 'must start with...' do
    page = 'my reply'
    page.must_start_with 'my reply'
    page.must_start_with 'my '
  end
end

答案 1 :(得分:1)

有很多方法可以在这里得到你想要的东西。最简单的方法是根本不要破坏断言,期望或匹配,只使用断言。因此,假设您已经定义了has_reply?方法,您可以使用它:

assert page.has_reply?("my reply")

但是,这并没有为您提供所要求的must_have_reply语法。我怀疑你真的有has_reply?方法。那么,让我们开始。

您问“如何获得对主题的引用(即页面对象)”。在这种情况下,主题是定义must_have_reply方法的对象。因此,您应该使用this而不是subject。但它并不像所有那样直截了当。匹配器使用通常的断言(assert_equalrefute_equal)或期望(must_be_equalwont_be_equal)添加我们没有的间接级别。如果你想编写一个Matcher,你需要实现Matcher API。

幸运的是,您并不需要实现API。由于您似乎已经打算依赖Cabybara的have_css匹配器,我们可以简单地使用Capybara的HaveSelector类并让它实现适当的API。我们只需要使用返回HaveSelector对象的方法创建自己的Matchers模块。

# Require Minitest Matchers to make this all work
require "minitest/matchers"
# Require Capybara's matchers so you can use them
require "capybara/rspec/matchers"

# Create your own matchers module
module YourApp
  module Matchers
    def have_reply text
      # Return a properly configured HaveSelector instance
      Capybara::RSpecMatchers::HaveSelector.new(:css, ".comment_body", :text => text)
    end

    # Register module using minitest-matcher syntax
    def self.included base
      instance_methods.each do |name|
        base.register_matcher name, name
      end
    end
  end
end

然后,在您的minitest_helper.rb文件中,您可以包含您的Matchers模块,以便您可以使用它。 (此代码将在所有测试中包含匹配器。)

class MiniTest::Rails::ActiveSupport::TestCase
  # Include your module in the test case
  include YourApp::Matchers
end

Minitest Matchers完成所有艰难的工作。您现在可以使用匹配器作为断言:

def test_using_an_assertion
  visit root_path
  assert_have_reply page, "my reply"
end

或者,您可以使用匹配器作为期望:

it "is an expectation" do
  visit root_path
  page.must_have_reply "my reply"
end

最后你可以将它与主题一起使用:

describe "with a subject" do
  before  { visit root_path }
  subject { page }

  it { must have_reply("my reply") }
  must { have_reply "my reply" }
end

重要:为了实现这一点,您必须使用'gem minitest-matchers','> = 1.2.0',因为在该gem的早期版本中未定义register_matcher。