定义自己的RSpec matcher

April 04, 2015 20:42


Examples

统计一个数组中匹配字符串的数量

ary = %w{aa ab bb bc}

# 通常会这样做
expect(ary.select {|s| s =~ /^a/ }.count).to eq(2)

# 如果有一个定义好的matcher,可以这样做
expect(ary).to match_total(/^a/, 2)

又如,我们测试一个API返回格式是否正确

# 通常的做法是
expect(response).to be_ok
expect(JSON.parse(response.body)['items']).to be_a(Array)

# 使用matcher,可以这样写
expect(response).to be_correct_data

通过上面的例子可以看出,使用matcher可以减少重复代码,并使代码更易懂

Do it

可以通过如下方式定义一个matcher

RSpec::Matchers.define :match_total do |regexp, total|
  match do |actual|
    actual.select {|str| str =~ regexp }.count == total
  end
end

RSpec.describe :my_test do
  it 'case' do
    expect(%w{aa ab bc ba}).to match_total(/^a/, 2)
  end
end

通常我会做成一个module,在需要的地方加载

module XyzMatcher
  exntend RSpec::Matchers::DSL

  define :be_correct_response do
    match do |response|
      response.status == 200 && JSON.parse(response.body)['items'].is_a?(Array) 
    end

    # 定义matcher失败的信息
    failure_message do |response|
      "Wrong response, expect status equal 200 and items be array, but not"
    end
  end
end

# 通过下面的方式来加载
RSpec.configure do |config|
  config.include XyzMatcher, type: :xyz  
end

# 或是手动include
RSpec.describe :xyz do
  include XyzMatcher
end

Reference

Comments: