RSpec自定义diffable匹配器

时间:2015-09-09 10:27:55

标签: ruby rspec

我在RSpec中有一个自定义匹配器,忽略空格/换行符,只匹配内容:

RSpec::Matchers.define :be_matching_content do |expected|
  match do |actual|
    actual.gsub(/\s/,'').should == expected.gsub(/\s/,'')
  end

  diffable
end

我可以这样使用它:

    body = "   some data   \n more data"
    body.should be_matching_content("some data\nmore wrong data")

但是,当测试失败时(如上所述),diff输出看起来不太好:

   -some data
   -more wrong data
   +   some data   
   + more data

是否可以配置diffable输出?第一行some data是正确的,但第二行more wrong data是错误的。仅将第二行作为失败的根本原因是非常有用的。

3 个答案:

答案 0 :(得分:11)

我相信您应该在RSpec中禁用默认diffable行为并替换您自己的实现:

RSpec::Matchers.define :be_matching_content do |expected|
  match do |actual|
    @stripped_actual = actual.gsub(/\s/,'')
    @stripped_expected = expected.gsub(/\s/,'')
    expect(@stripped_actual).to eq @stripped_expected
  end

  failure_message do |actual|
    message = "expected that #{@stripped_actual} would match #{@stripped_expected}"
    message += "\nDiff:" + differ.diff_as_string(@stripped_actual, @stripped_expected)
    message
  end

  def differ
    RSpec::Support::Differ.new(
        :object_preparer => lambda { |object| RSpec::Matchers::Composable.surface_descriptions_in(object) },
        :color => RSpec::Matchers.configuration.color?
    )
  end
end

RSpec.describe 'something'do
  it 'should diff correctly' do
    body = "   some data   \n more data"
    expect(body).to be_matching_content("some data\nmore wrong data")
  end
end

产生以下内容:

Failures:

  1) something should diff correctly
     Failure/Error: expect(body).to be_matching_content("some data\nmore wrong data")
       expected that somedatamoredata would match somedatamorewrongdata
       Diff:
       @@ -1,2 +1,2 @@
       -somedatamorewrongdata
       +somedatamoredata

如果需要,可以使用自定义不同,甚至可以将整个匹配器重新实现为对diff命令的系统调用,如下所示:

♥ diff -uw --label expected --label actual <(echo "   some data    \n more data") <(echo "some data\nmore wrong data")
--- expected
+++ actual
@@ -1,2 +1,2 @@
    some data    
- more data
+more wrong data

干杯!

答案 1 :(得分:4)

您可以覆盖生成差异时将使用的expectedactual方法。在此示例中,我们将期望值和实际值存储为实例变量,并定义返回实例变量的方法:

RSpec::Matchers.define :be_matching_content do |expected_raw|
  match do |actual_raw|
    @actual = actual_raw.gsub(/\s/,'')
    @expected = expected_raw.gsub(/\s/,'') 
    expect(expected).to eq(@actual)
  end

  diffable
  attr_reader :actual, :expected
end

另一个例子是匹配两种不同类型对象中的特定属性。 (在这种情况下,预期对象是Client模型。)

RSpec::Matchers.define :have_attributes_of_v1_client do |expected_client|
  match do |actual_object|
    @expected = client_attributes(expected_client)
    @actual = actual_object.attributes
    expect(actual_object).to have_attributes(@expected)
  end

  diffable
  attr_reader :actual, :expected

  def failure_message
    "expected attributes of a V1 Client view row, but they do not match"
  end

  def client_attributes(client)
    {
      "id" => client.id,
      "client_type" => client.client_type.name,
      "username" => client.username,
      "active" => client.active?,
    }
  end
end

示例失败如下所示:

Failure/Error: is_expected.to have_attributes_of_v1_client(client_active_partner)
  expected attributes of a V1 Client view row, but they do not match
  Diff:
  @@ -1,6 +1,6 @@
   "active" => true,
  -"client_type" => #<ClientType id: 2, name: "ContentPartner">,
  +"client_type" => "ContentPartner",
   "id" => 11,

答案 2 :(得分:1)

可以使用名为diffy的宝石。

但是它逐行遍历一个字符串并比较它们,所以不是删除所有空格,而是用换行符替换任意数量的空格并区分这些条目。

这是你可以做一些改善你的差异的例子。我并不是100%确定将其插入代码的位置。

def compare(str1, str2)
  str1 = break_string(str1)
  str2 = break_string(str2)
  return true if str1 == str2
  puts Diffy::Diff.new(str1, str2).to_s
  return false
end

def break_string(str)
  str.gsub(/\s+/,"\n")
end

可以设置diffy gem以产生适合终端的颜色输出。

使用此代码可以像这样工作

str1 = 'extra some                 content'
str2 = 'extra more content'
puts compare(str1, str2)

这会打印

 extra
 -some   # red in terminal
 +more   # green in terminal
 content
 \ No newline at end of file