Giải pháp so sánh JSON
Mang lại một Diff sạch nhưng có khả năng lớn:
actual = JSON.parse(response.body, symbolize_names: true)
expected = { foo: "bar" }
expect(actual).to eq expected
Ví dụ về đầu ra giao diện điều khiển từ dữ liệu thực:
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, ...}
(Cảm ơn bình luận của @floatingrock)
Giải pháp so sánh chuỗi
Nếu bạn muốn một giải pháp vỏ sắt, bạn nên tránh sử dụng các trình phân tích cú pháp có thể đưa ra sự bình đẳng dương tính giả; so sánh cơ thể phản hồi với một chuỗi. ví dụ:
actual = response.body
expected = ({ foo: "bar" }).to_json
expect(actual).to eq expected
Nhưng giải pháp thứ hai này ít thân thiện hơn vì nó sử dụng JSON được tuần tự hóa, bao gồm rất nhiều dấu ngoặc kép được thoát.
Giải pháp so khớp tùy chỉnh
Tôi có xu hướng tự viết cho mình một công cụ đối sánh tùy chỉnh thực hiện công việc xác định chính xác vị trí đệ quy mà các đường dẫn JSON khác nhau tốt hơn nhiều. Thêm phần sau vào macro rspec của bạn:
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
Ví dụ về cách sử dụng 1:
expect_response(response, :no_content)
Ví dụ về cách sử dụng 2:
expect_response(response, :ok, {
story: {
id: 1,
name: "Shire Burning",
revisions: [ ... ],
}
})
Ví dụ đầu ra:
Type String expected "Shire Burning" but got "Shire Burnin" at path: /:story/:name
Một ví dụ đầu ra khác để chứng minh sự không khớp sâu trong một mảng lồng nhau:
Type Integer expected 2 but got 1 at path: /:story/:revisions[0]/:version
Như bạn có thể thấy, đầu ra cho bạn biết CHÍNH XÁC nơi sửa lỗi JSON dự kiến của bạn.