Solusi perbandingan JSON
Menghasilkan Diff yang bersih namun berpotensi besar:
actual = JSON.parse(response.body, symbolize_names: true)
expected = { foo: "bar" }
expect(actual).to eq expected
Contoh output konsol dari data nyata:
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, ...}
(Terima kasih untuk komentar oleh @floatingrock)
Solusi perbandingan string
Jika Anda menginginkan solusi berbalut besi, Anda harus menghindari penggunaan parser yang dapat memperkenalkan kesetaraan positif palsu; bandingkan tubuh respons terhadap string. misalnya:
actual = response.body
expected = ({ foo: "bar" }).to_json
expect(actual).to eq expected
Tetapi solusi kedua ini kurang ramah secara visual karena menggunakan JSON berseri yang akan mencakup banyak tanda kutip yang lolos.
Solusi pencocokan khusus
Saya cenderung menulis sendiri pencocokan kustom yang melakukan pekerjaan yang jauh lebih baik untuk menentukan dengan tepat di mana slot rekursif jalur JSON berbeda. Tambahkan berikut ini ke makro rspec Anda:
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
Contoh penggunaan 1:
expect_response(response, :no_content)
Contoh penggunaan 2:
expect_response(response, :ok, {
story: {
id: 1,
name: "Shire Burning",
revisions: [ ... ],
}
})
Contoh output:
Type String expected "Shire Burning" but got "Shire Burnin" at path: /:story/:name
Contoh output lain untuk menunjukkan ketidakcocokan jauh di dalam array bersarang:
Type Integer expected 2 but got 1 at path: /:story/:revisions[0]/:version
Seperti yang Anda lihat, output memberitahu Anda PERSIS di mana untuk memperbaiki JSON yang Anda harapkan.