JSON karşılaştırma çözümü
Temiz ancak potansiyel olarak büyük bir Diff verir:
actual = JSON.parse(response.body, symbolize_names: true)
expected = { foo: "bar" }
expect(actual).to eq expected
Gerçek verilerden konsol çıktısı örneği:
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, ...}
(@Floatingrock tarafından yapılan yorum için teşekkürler)
Dize karşılaştırma çözümü
Demir kaplı bir çözüm istiyorsanız, yanlış pozitif eşitliğe yol açabilecek ayrıştırıcılar kullanmaktan kaçınmalısınız; yanıt gövdesini bir dizeyle karşılaştırın. Örneğin:
actual = response.body
expected = ({ foo: "bar" }).to_json
expect(actual).to eq expected
Ancak bu ikinci çözüm, birçok çıkış karakterli tırnak işareti içeren serileştirilmiş JSON kullandığından daha az görsel dostudur.
Özel eşleştirici çözümü
Kendime, JSON yollarının tam olarak hangi yinelemeli yuvada farklı olduğunu saptamak için çok daha iyi bir iş çıkaran özel bir eşleştirici yazma eğilimindeyim. Aşağıdakileri rspec makrolarınıza ekleyin:
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
Kullanım 1 örneği:
expect_response(response, :no_content)
Kullanım 2 örneği:
expect_response(response, :ok, {
story: {
id: 1,
name: "Shire Burning",
revisions: [ ... ],
}
})
Örnek çıktı:
Type String expected "Shire Burning" but got "Shire Burnin" at path: /:story/:name
İç içe geçmiş bir dizide derin bir uyuşmazlığı göstermek için başka bir örnek çıktı:
Type Integer expected 2 but got 1 at path: /:story/:revisions[0]/:version
Gördüğünüz gibi, çıktı size tam olarak beklenen JSON'unuzu nerede düzelteceğinizi söyler.