2015-09-09 8 views
5

ich einen benutzerdefinierten Matcher in RSpec habe, die Whitespaces/Zeilenumbrüche ignoriert, und nur Spiele Inhalt:RSpec benutzerdefinierte diffable Matcher

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

    diffable 
end 

ich es wie folgt verwenden:

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

Wenn jedoch ein Test fehlschlägt (wie die oben), sieht die Ausgabe von diff nicht gut:

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

Ist es möglich, den diffable Ausgang zu konfigurieren ? Die erste Zeile some data ist richtig, aber die zweite more wrong data ist falsch. Es wäre sehr nützlich, nur die zweite Zeile als Hauptursache des Fehlers zu bekommen.

Antwort

8

Ich glaube, Sie Standard diffable Verhalten in RSpec deaktivieren sollte und eine eigene Implementierung ersetzen:

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 

erzeugt folgendes:

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 

Sie benutzerdefinierte abweichen, wenn Sie möchten, verwenden können, auch diese ganze Matcher diff Befehl, um so etwas zu einem Systemaufruf neu implementieren:

♥ 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 

Prost!

1

Es gibt ein Juwel namens diffy, das verwendet werden kann.

Aber es geht Zeile für Zeile durch eine Zeichenfolge und vergleicht sie so, anstatt alle Leerzeichen zu entfernen, könnten Sie eine beliebige Anzahl von Leerzeichen mit einem Zeilenumbruch ersetzen und diese Einträge diff.

Dies ist ein Beispiel für etwas, was Sie tun könnten, um Ihre Diffs ein wenig zu verbessern. Ich bin mir nicht 100% sicher, wo ich das in deinen Code einfügen soll.

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 

Der Diffy-Edelstein kann so eingestellt werden, dass er eine für das Terminal geeignete Farbausgabe liefert.

diesen Code verwenden wie dieses

str1 = 'extra some     content' 
str2 = 'extra more content' 
puts compare(str1, str2) 
funktionieren würde

dies würde drucken

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

Sie können die Methoden expected und actual überschreiben, die dann beim Generieren des Diffs verwendet werden. In diesem Beispiel speichern wir die erwarteten und tatsächlichen Werte als Instanzvariablen und Methoden definieren, die die Instanzvariablen zurück:

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 

Ein weiteres Beispiel für bestimmte Attribute in zwei verschiedene Arten von Objekten anzupassen ist. (Das erwartete Objekt ist in diesem Fall ein Modell 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 

Beispiel Scheitern sieht wie folgt aus:

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, 
+1

Hinweis: Dies ist nur in den rspec docs erwähnt bei ab Version 3.4. Gemäß den Dokumenten benötigen Sie auch nicht den 'attr_reader', wenn Sie' @ actual' als Instanzvariablennamen verwenden. –

Verwandte Themen