В Rspec я тестирую хэш, содержащий такой массив:
subject { described_class.call(build: build_one, user:)
it 'returns the correct data' do
response = subject
expected_response = {
id: build_one.id,
status: {
key: 'active',
name: 'Active'
},
build_type: 'SystemBuild',
calculated_type_id: CalculatedType.standard.id,
build_time: build_one.build_time,
summary: 'Lorem ipsum dolor sit amet...',
data: [
{id: '1', name: '', parent: ''},
{id: '1.1', name: 'Calc type 1', parent: '1'},
{id: '1.2', name: 'Calc type 2', parent: '1'},
{id: '1.3', name: 'Calc type 3', parent: '1'},
{id: '1.1.1', name: 'Value 1', parent: '1.1'},
{id: '1.1.2', name: 'Value 2', parent: '1.1'},
{id: '1.2.1', name: 'Value 3', parent: '1.2'},
{id: '1.3.1', name: 'Value 4', parent: '1.3'},
{id: '1.3.2', name: 'Value 5', parent: '1.3'},
{id: '1.3.3', name: 'Value 6', parent: '1.3'}
]
}
expect(response).to match(expected_response)
end
Моя проблема в том, что массив data
не обязательно находится в том же порядке, как я написал в expected_response
.
Я, конечно, мог бы изменить порядок в expected_response
, но я не хочу его ограничивать таким образом. Дело в том, что для приложения порядок массива вообще не имеет значения, и изменение других частей приложения может изменить порядок. Важно лишь то, чтобы в массиве присутствовали все элементы.
Когда я запускаю тест, я получаю следующее:
Diff:
:build_time: 2024-06-22 10:17:55.0000000000 -0700,
:build_type: "SystemType",
:calculated_type_id: 3,
:id => 234,
-:data => [{:id=>"1", :name=>"", :parent=>""}, {:id=>"1.1", :name=>"Calc type 1", :parent=>"1"}, {:id=>"1.2", :name=>"Calc type 2", :parent=>"1"}, {:id=>"1.3", :name=>"Calc type 3", :parent=>"1"}, {:id=>"1.1.1", :name=>"Value 1", :parent=>"1.1"}, {:id=>"1.1.2", :name=>"Value 2", :parent=>"1.1"}, {:id=>"1.2.1", :name=>"Value 3", :parent=>"1.2"}, {:id=>"1.3.1", :name=>"Value 4", :parent=>"1.3"}, {:id=>"1.3.2", :name=>"Value 5", :parent=>"1.3"}, {:id=>"1.3.3", :name=>"Value 6", :parent=>"1.3"}]
+:data => [{:id=>"1", :name=>"", :parent=>""}, {:id=>"1.1", :name=>"Calc type 1", :parent=>"1"}, {:id=>"1.2", :name=>"Calc type 2", :parent=>"1"}, {:id=>"1.3", :name=>"Calc type 3", :parent=>"1"}, {:id=>"1.1.1", :name=>"Value 1", :parent=>"1.1"}, {:id=>"1.2.1", :name=>"Value 3", :parent=>"1.2"}, {:id=>"1.3.2", :name=>"Value 5", :parent=>"1.3"}, {:id=>"1.1.2", :name=>"Value 2", :parent=>"1.1"}, {:id=>"1.3.1", :name=>"Value 4", :parent=>"1.3"}, {:id=>"1.3.3", :name=>"Value 6", :parent=>"1.3"}]
:status => {:key=>"active", :name=>"Active"},
:summary => "Lorem ipsum dolor sit amet..."
Я думал, что match(...)
проигнорирует порядок массива data
и просто проверит существование всех элементов. Есть ли способ сделать это без необходимости проверять каждый элемент хеша?
Если порядок для вас не имеет значения, я бы просто отсортировал массивы по переменным expected_response
и response
одинаково:
expected_response[:data] = expected_response[:data].sort_by{|x| x[:id]}
response[:data] = response[:data].sort_by{|x| x[:id]}
expect(response).to match(expected_response)
В Rspec есть match_array() (псевдоним contains_exactly()), который игнорирует порядок массивов.
При использовании match со структурой данных (массивом или хешем) вы можете использовать другие средства сопоставления RSpec внутри этой структуры, например содержит_точно:
let(:expected) do
{
data: contain_exactly(1, 2, 3)
}
end
it 'matches' do
expect({ data: [2, 3, 1] }).to match(expected)
end
Вы можете использовать сопоставитель contains_exactly. Просто примените его в ожидаемом ответе таким образом
expected_response = {
id: 10,
status: 'ok',
data: contain_exactly(
{ id: 1 },
{ id: 2 },
),
}
response = {
status: 'ok',
data: [
{ id: 2 },
{ id: 1 },
],
id: 10,
}
expect(response).to match expected_response
Или примените match_array. В примере выше это будет выглядеть так match_array([{id: 1}, {id: 2}])
Оба сопоставителя игнорируют порядок массива
Хорошая точка зрения. Я надеялся, что для этого будет какой-то «встроенный» сопоставитель RSpec, но если я не смогу его найти, я сделаю это.