7

我的测试中有一行:

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

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

4

2 回答 2

7

有一个小例子,你可以创建一个类,它应该响应一组方法matches?, failure_message_for_should, failure_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
于 2012-09-04T16:32:07.537 回答
1

有很多方法可以在这里得到你想要的。最简单的方法是完全不用断言、期望或匹配器,而只使用断言。所以,假设你已经has_reply?定义了方法,你可以使用这个:

assert page.has_reply?("my reply")

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

您问“如何获取对主题(即页面对象)的引用”。在这种情况下,主题是must_have_reply定义方法的对象。因此,您应该使用this而不是subject. 但它并不像所有这些那么简单。assert_equal匹配器添加了我们在通常的断言 ( , refute_equal) 或期望 ( must_be_equal, )中没有的间接级别wont_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' 因为 register_matcher 未在该 gem 的早期版本中定义。

于 2012-09-04T23:43:31.130 回答