Rspec: "array.should == another_array", aber ohne Rücksicht auf die Reihenfolge

235

Ich möchte oft Arrays vergleichen und sicherstellen, dass sie dieselben Elemente in beliebiger Reihenfolge enthalten. Gibt es eine prägnante Möglichkeit, dies in RSpec zu tun?

Hier sind Methoden, die nicht akzeptabel sind:

#to_set

Beispielsweise:

expect(array.to_set).to eq another_array.to_set

oder

array.to_set.should == another_array.to_set

Dies schlägt fehl, wenn die Arrays doppelte Elemente enthalten.

#sort

Beispielsweise:

expect(array.sort).to eq another_array.sort

oder

array.sort.should == another_array.sort

Dies schlägt fehl, wenn die Arrays-Elemente nicht implementiert werden #<=>

Nicholaides
quelle
7
Nicht zu schlau, sondern zu vergleichen to_setund sizetatsächlich nicht zu tun, was Sie wollen. ZB würde [a, b, b] mit [a, a, b] übereinstimmen. Prost!
Jo Liss
3
Für diejenigen, die hier gestolpert sind und sich das Gegenteil gefragt haben: Die Reihenfolge sollte dieselbe sein . Verwenden Sie den eqMatcher, zBexpect([1, 2]).to_not eq([2, 1])
Dennis

Antworten:

263

Versuchen array.should =~ another_array

Die beste Dokumentation dazu ist der Code selbst, der hier ist .

x1a4
quelle
Dies berücksichtigt nicht die Reihenfolge, daher ist dies keine akzeptable Antwort, oder? Zitat aus den Dokumenten : Passes if actual contains all of the expected regardless of order..
Joshua Muheim
16
Titel dieses Beitrags: "Rspec:" array.should == another_array ", aber ohne Rücksicht auf die Bestellung"
x1a4
3
Dies ist jetzt offiziell unter Operator Matchers
Kelvin
7
Wenn Sie die neue "Expect" -Syntax in rspec 3.0 verwenden, lesen Sie die Antwort von @JoshKovach.
Clozach
46
Rspec 3.0 Syntax ist zu expect([1, 2, 3]).to match_array([2, 1, 3])sehen: stackoverflow.com/a/19436763/33226
Gavin Miller
238

Seit RSpec 2.11 können Sie auch verwenden match_array.

array.should match_array(another_array)

Was in einigen Fällen besser lesbar sein könnte.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])
Valentin Nemcev
quelle
8
yup, habe gerade auf Rails 4 aktualisiert und = ~ hat aufgehört zu arbeiten, wo match_array gut funktioniert, danke!
opsb
2
Ich weiß nicht, ob das besser lesbar ist. Jetzt liest es sich so, als ob es genau übereinstimmen sollte, aber es ist nicht so. Das vorherige Kringeln war vage genug, um für ein Array nichts zu bedeuten, also hatte ich nicht das Vorurteil. Vielleicht bin ich es nur.
Trejkaz
1
Für "genau" haben Sie immer eq(), also denke ich, match_array()ist vage genug für mich.
Awendt
Bei geordneten Listen funktioniert das bei mir nicht. Es glaubt, dass Listen, die dieselben Elemente in einer anderen Reihenfolge haben, gleich sind. :-(
Djangofan
FWIW match_arrayist ein Alias ​​für contain_exactly( Dokumentation )
Ruy Diaz
136

Ich habe festgestellt =~, dass es unvorhersehbar ist, und es ist ohne ersichtlichen Grund gescheitert. Nach 2.14 sollten Sie wahrscheinlich verwenden

expect([1, 2, 3]).to match_array([2, 3, 1])
Josh Kovach
quelle
17
Auch gültig nach 3.0 : expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/…
Clozach
13

Verwenden Sie match_array, das ein anderes Array als Argument verwendet oder contain_exactlyjedes Element als separates Argument verwendet und manchmal für die Lesbarkeit hilfreich ist. ( docs )

Beispiele:

expect([1, 2, 3]).to match_array [3, 2, 1]

oder

expect([1, 2, 3]).to contain_exactly 3, 2, 1
Nicholaides
quelle
3

Für RSpec 3 verwenden Sie contain_exactly:

Weitere Informationen finden Sie unter https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher. Hier ist jedoch ein Auszug:

Der Matcher "include_exactly" bietet eine Möglichkeit, Arrays so gegeneinander zu testen, dass Unterschiede in der Reihenfolge zwischen dem tatsächlichen und dem erwarteten Array nicht berücksichtigt werden. Beispielsweise:

    expect([1, 2, 3]).to    contain_exactly(2, 3, 1) # pass
    expect([:a, :c, :b]).to contain_exactly(:a, :c ) # fail

Wie andere darauf hingewiesen haben, sollten Sie, wenn Sie das Gegenteil behaupten möchten, dass die Arrays sowohl dem Inhalt als auch der Reihenfolge entsprechen sollten, verwenden eq, dh:

    expect([1, 2, 3]).to    eq([1, 2, 3]) # pass
    expect([1, 2, 3]).to    eq([2, 3, 1]) # fail
Tim Diggins
quelle
1

nicht sehr gut dokumentiert, aber ich habe trotzdem Links hinzugefügt:

Rspec3- Dokumente

expect(actual).to eq(expected)


Rspec2- Dokumente

expect([1, 2, 3]).to match_array([2, 3, 1])

Blair Anderson
quelle
11
Beide erwarten (tatsächlich) .to eq (erwartet) und erwarten (tatsächlich) .to match_array (erwartet) arbeiten in rspec3, aber sie machen verschiedene Dinge. #match_array ignoriert die Reihenfolge, #eq nicht.
Gucki
1
Dies beantwortet die Frage nicht, da das OP ausdrücklich darum gebeten hat, die Bestellung zu ignorieren.
NobodysNightmare
Ja! Das hat bei mir funktioniert. Ein Vergleich, der fehlschlägt, wenn die Reihenfolge der Elemente nicht identisch ist. Danke dir! Ich beziehe mich auf die .to eqMethode, nicht auf die match_array.
Djangofan