Rozwiązanie porównawcze JSON
Daje czysty, ale potencjalnie duży Diff:
actual = JSON.parse(response.body, symbolize_names: true)
expected = { foo: "bar" }
expect(actual).to eq expected
Przykład danych wyjściowych konsoli z rzeczywistych danych:
expected: {:story=>{:id=>1, :name=>"The Shire"}}
got: {:story=>{:id=>1, :name=>"The Shire", :description=>nil, :body=>nil, :number=>1}}
(compared using ==)
Diff:
@@ -1,2 +1,2 @@
-:story => {:id=>1, :name=>"The Shire"},
+:story => {:id=>1, :name=>"The Shire", :description=>nil, ...}
(Dzięki komentarzowi @floatingrock)
Rozwiązanie do porównywania ciągów
Jeśli chcesz uzyskać żelazne rozwiązanie, powinieneś unikać używania parserów, które mogą wprowadzić fałszywie dodatnią równość; porównaj treść odpowiedzi z ciągiem. na przykład:
actual = response.body
expected = ({ foo: "bar" }).to_json
expect(actual).to eq expected
Ale to drugie rozwiązanie jest mniej przyjazne wizualnie, ponieważ wykorzystuje serializowany kod JSON, który zawiera wiele cudzysłowów.
Niestandardowe rozwiązanie dopasowujące
Zwykle piszę sobie niestandardowy element dopasowujący, który znacznie lepiej radzi sobie z dokładnym wskazaniem, w którym dokładnie rekurencyjnym slocie różnią się ścieżki JSON. Dodaj następujące elementy do swoich makr rspec:
def expect_response(actual, expected_status, expected_body = nil)
expect(response).to have_http_status(expected_status)
if expected_body
body = JSON.parse(actual.body, symbolize_names: true)
expect_json_eq(body, expected_body)
end
end
def expect_json_eq(actual, expected, path = "")
expect(actual.class).to eq(expected.class), "Type mismatch at path: #{path}"
if expected.class == Hash
expect(actual.keys).to match_array(expected.keys), "Keys mismatch at path: #{path}"
expected.keys.each do |key|
expect_json_eq(actual[key], expected[key], "#{path}/:#{key}")
end
elsif expected.class == Array
expected.each_with_index do |e, index|
expect_json_eq(actual[index], expected[index], "#{path}[#{index}]")
end
else
expect(actual).to eq(expected), "Type #{expected.class} expected #{expected.inspect} but got #{actual.inspect} at path: #{path}"
end
end
Przykład użycia 1:
expect_response(response, :no_content)
Przykład użycia 2:
expect_response(response, :ok, {
story: {
id: 1,
name: "Shire Burning",
revisions: [ ... ],
}
})
Przykładowe dane wyjściowe:
Type String expected "Shire Burning" but got "Shire Burnin" at path: /:story/:name
Inne przykładowe dane wyjściowe pokazujące niezgodność głęboko w zagnieżdżonej tablicy:
Type Integer expected 2 but got 1 at path: /:story/:revisions[0]/:version
Jak widać, dane wyjściowe mówią DOKŁADNIE, gdzie naprawić oczekiwany kod JSON.