Rspec: "array.should == another_array", mas sem preocupação com a ordem

235

Frequentemente, quero comparar matrizes e garantir que elas contenham os mesmos elementos, em qualquer ordem. Existe uma maneira concisa de fazer isso no RSpec?

Aqui estão métodos que não são aceitáveis:

#to_set

Por exemplo:

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

ou

array.to_set.should == another_array.to_set

Isso falha quando as matrizes contêm itens duplicados.

#sort

Por exemplo:

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

ou

array.sort.should == another_array.sort

Isso falha quando os elementos de matriz não implementam #<=>

nicholaides
fonte
7
Não é esperto, mas comparar to_sete sizerealmente não faz o que você deseja. Por exemplo, [a, b, b] corresponderia a [a, a, b]. Felicidades!
precisa saber é o seguinte
3
Para quem tropeçou aqui imaginando o oposto: a ordem deve ser a mesma . Use o eqmarcador, por exemplo,expect([1, 2]).to_not eq([2, 1])
Dennis

Respostas:

263

Experimentar array.should =~ another_array

A melhor documentação sobre isso que posso encontrar é o próprio código, que está aqui .

x1a4
fonte
Isso não leva em conta o pedido, portanto, essa não é uma resposta aceitável, é? Citar os docs : Passes if actual contains all of the expected regardless of order..
Joshua Muheim
16
Título desta publicação: "Rspec:" array.should == another_array ", mas sem preocupação com a ordem"
x1a4 22/01
3
Este é agora oficialmente documentado sob matchers operador
Kelvin
7
Se você estiver usando a nova sintaxe "expect" encontrada no rspec 3.0, consulte a resposta de @JoshKovach.
clozach
46
Rspec 3.0 sintaxe é expect([1, 2, 3]).to match_array([2, 1, 3])ver: stackoverflow.com/a/19436763/33226
Gavin Miller
238

Desde o RSpec 2.11, você também pode usar match_array.

array.should match_array(another_array)

O que poderia ser mais legível em alguns casos.

[1, 2, 3].should =~ [2, 3, 1]
# vs
[1, 2, 3].should match_array([2, 3, 1])
Valentin Nemcev
fonte
8
Sim, apenas atualizei para os trilhos 4 e = ~ parou de funcionar onde match_array funciona bem, obrigado!
Opsb dec
2
Não sei se isso é mais legível. Agora parece que deve ser uma correspondência exata, mas não é. O rabisco anterior era vago o suficiente para não significar nada para uma matriz, então eu não tinha o preconceito. Talvez seja só eu.
Trejkaz
1
Para "exato", você sempre tem eq(), então acho que match_array()é vago o suficiente para mim.
awendt
Isso não funciona para mim nas listas ordenadas. Ele acha que as listas, que têm os mesmos itens em uma ordem diferente, são iguais. :-(
djangofan
FWIW match_arrayé um alias para contain_exactly( documentação )
Ruy Diaz
136

Eu achei =~imprevisível e falhou sem motivo aparente. Após a versão 2.14, você provavelmente deve usar

expect([1, 2, 3]).to match_array([2, 3, 1])
Josh Kovach
fonte
17
Também passado válida 3.0: expect([1, 2, 3]).to contain_exactly(2, 3, 1). relishapp.com/rspec/rspec-expectations/v/3-0/docs/...
clozach
13

Use match_array, que aceita outra matriz como argumento, ou contain_exactlyque aceita cada elemento como argumento separado e, às vezes, é útil para facilitar a leitura. ( docs )

Exemplos:

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

ou

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

Para o RSpec 3, use contain_exactly:

Consulte https://relishapp.com/rspec/rspec-expectations/v/3-2/docs/built-in-matchers/contain-exactly-matcher para obter detalhes, mas aqui está um extrato:

O match_exactly matcher fornece uma maneira de testar matrizes uns contra os outros de uma maneira que desconsidera diferenças na ordem entre a matriz real e a esperada. Por exemplo:

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

Como outros já apontaram, se você deseja afirmar o contrário, que as matrizes devem corresponder ao conteúdo e à ordem, use eq:

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

não está muito bem documentado, mas adicionei links de qualquer maneira:

Docs Rspec3

expect(actual).to eq(expected)


Docs Rspec2

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

Blair Anderson
fonte
11
Ambos esperam (real) .to eq (esperado) e esperam (real) .to match_array (esperado) funcionam no rspec3, mas estão fazendo coisas diferentes. #match_array ignora a ordem, enquanto #eq não.
gucki
1
Isso não responde à pergunta, pois o OP pediu especificamente para desconsiderar o pedido.
NobodysNightmare 19/05
Sim! Isso funcionou para mim. Uma comparação que falha se a ordem dos elementos não for a mesma. Obrigado! Refiro-me ao .to eqmétodo, não ao match_array.
djangofan