โซลูชันการเปรียบเทียบ JSON
ให้ผลต่างที่สะอาด แต่อาจมีขนาดใหญ่:
actual = JSON.parse(response.body, symbolize_names: true)
expected = { foo: "bar" }
expect(actual).to eq expected
ตัวอย่างของเอาต์พุตคอนโซลจากข้อมูลจริง:
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)
วิธีการเปรียบเทียบสตริง
หากคุณต้องการวิธีแก้ปัญหาที่หุ้มด้วยเหล็กคุณควรหลีกเลี่ยงการใช้ parsers ซึ่งอาจนำไปสู่ความเท่าเทียมในเชิงบวกที่ผิดพลาด เปรียบเทียบเนื้อหาการตอบสนองกับสตริง เช่น:
actual = response.body
expected = ({ foo: "bar" }).to_json
expect(actual).to eq expected
แต่โซลูชันที่สองนี้มีความเป็นมิตรต่อสายตาน้อยกว่าเนื่องจากใช้ JSON แบบอนุกรมซึ่งจะมีเครื่องหมายคำพูดที่ใช้ Escape จำนวนมาก
โซลูชัน matcher ที่กำหนดเอง
ฉันมักจะเขียน matcher แบบกำหนดเองที่ทำงานได้ดีขึ้นมากในการหาตำแหน่งที่สล็อตแบบเรียกซ้ำที่พา ธ JSON ต่างกัน เพิ่มสิ่งต่อไปนี้ในมาโคร 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
ตัวอย่างการใช้งาน 1:
expect_response(response, :no_content)
ตัวอย่างการใช้งาน 2:
expect_response(response, :ok, {
story: {
id: 1,
name: "Shire Burning",
revisions: [ ... ],
}
})
ตัวอย่างผลลัพธ์:
Type String expected "Shire Burning" but got "Shire Burnin" at path: /:story/:name
อีกตัวอย่างหนึ่งของการแสดงผลเพื่อแสดงให้เห็นถึงความไม่ตรงกันลึกลงไปในอาร์เรย์ที่ซ้อนกัน:
Type Integer expected 2 but got 1 at path: /:story/:revisions[0]/:version
ดังที่คุณเห็นผลลัพธ์จะแจ้งให้คุณทราบว่าจะแก้ไข JSON ของคุณได้จากที่ใด