Rspec: "array.should == another_array" mais sans souci d'ordre

235

Je veux souvent comparer des tableaux et m'assurer qu'ils contiennent les mêmes éléments, dans n'importe quel ordre. Existe-t-il un moyen concis de le faire dans RSpec?

Voici des méthodes qui ne sont pas acceptables:

#to_set

Par exemple:

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

ou

array.to_set.should == another_array.to_set

Cela échoue lorsque les tableaux contiennent des éléments en double.

#sort

Par exemple:

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

ou

array.sort.should == another_array.sort

Cela échoue lorsque les éléments des tableaux ne sont pas implémentés #<=>

nicholaides
la source
7
Pas pour smartass, mais en comparant to_setet en sizefait ne fait pas ce que vous voulez. Par exemple [a, b, b] correspondrait à [a, a, b]. À votre santé!
Jo Liss
3
Pour ceux qui ont trébuché ici se demandant le contraire: l' ordre devrait être le même . Utilisez le eqmatcher, par exempleexpect([1, 2]).to_not eq([2, 1])
Dennis

Réponses:

263

Essayer array.should =~ another_array

La meilleure documentation à ce sujet que je peux trouver est le code lui-même, qui est ici .

x1a4
la source
Cela ne tient pas compte de la commande, donc ce n'est pas une réponse acceptable, n'est-ce pas? Citation du docs : Passes if actual contains all of the expected regardless of order..
Joshua Muheim
16
Titre de cet article: "Rspec:" array.should == another_array "mais sans souci de commande"
x1a4
3
Ceci est maintenant officiellement documenté sous les opérateurs de correspondance
Kelvin
7
Si vous utilisez la nouvelle syntaxe "expect" trouvée dans rspec 3.0, consultez la réponse de @JoshKovach.
clozach
46
La syntaxe de Rspec 3.0 est la suivante expect([1, 2, 3]).to match_array([2, 1, 3]): stackoverflow.com/a/19436763/33226
Gavin Miller
238

Depuis RSpec 2.11, vous pouvez également utiliser match_array.

array.should match_array(another_array)

Ce qui pourrait être plus lisible dans certains cas.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])
Valentin Nemcev
la source
8
yup, juste mis à niveau vers les rails 4 et = ~ a cessé de fonctionner où match_array fonctionne bien, merci!
opsb
2
Je ne sais pas si c'est plus lisible. Maintenant, il semble que ce devrait être une correspondance exacte, mais ce n'est pas le cas. Le squiggle précédent était suffisamment vague pour ne rien signifier pour un tableau, donc je n'avais pas l'idée préconçue. C'est peut-être juste moi.
Trejkaz
1
Pour "exact", vous l'avez toujours fait eq(), donc je suppose que match_array()c'est assez vague pour moi.
awendt
Cela ne fonctionne pas pour moi sur les listes ordonnées. Il pense que les listes, qui ont les mêmes éléments dans un ordre différent, sont les mêmes. :-(
djangofan
FWIW match_arrayest un alias pour contain_exactly( documentation )
Ruy Diaz
136

Je l'ai trouvé =~imprévisible et il a échoué sans raison apparente. Après 2.14, vous devriez probablement utiliser

expect([1, 2, 3]).to match_array([2, 3, 1])
Josh Kovach
la source
17
En outre passé valide 3.0: expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/…
clozach
13

Utilisez match_array, qui prend un autre tableau comme argument, ou contain_exactly, qui prend chaque élément comme argument séparé, et est parfois utile pour la lisibilité. ( documents )

Exemples:

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

ou

expect([1, 2, 3]).to contain_exactly 3, 2, 1
nicholaides
la source
3

Pour l'utilisation de RSpec 3 contain_exactly:

Voir https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher pour plus de détails, mais voici un extrait:

Le matcher contain_exactly fournit un moyen de tester les tableaux les uns contre les autres d'une manière qui ne tient pas compte des différences dans l'ordre entre le tableau réel et le tableau attendu. Par exemple:

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

Comme d'autres l'ont souligné, si vous voulez affirmer le contraire, que les tableaux doivent correspondre à la fois au contenu et à l'ordre, alors utilisez eq, c'est-à-dire:

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

pas très bien documenté mais j'ai quand même ajouté des liens:

Rspec3 docs

expect(actual).to eq(expected)


Rspec2 docs

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

Blair Anderson
la source
12
Les deux attendent (réel) .to eq (attendu) et attendent (réel) .to match_array (attendu) fonctionnent dans rspec3, mais ils font des choses différentes. #match_array ignore l'ordre, tandis que #eq ne le fait pas.
gucki
1
Cela ne répond pas à la question, car le PO a expressément demandé de ne pas tenir compte de l'ordonnance.
NobodysNightmare
Oui! Cela a fonctionné pour moi. Une comparaison qui échoue si l'ordre des éléments n'est pas le même. Je vous remercie! Je me réfère à la .to eqméthode, pas à la match_array.
djangofan