Bagaimana untuk memeriksa respon JSON menggunakan RSpec?

Saya punya kode berikut di controller:

format.json { render :json => { 
        :flashcard  => @flashcard,
        :lesson     => @lesson,
        :success    => true
} 

Saya RSpec controller test saya ingin memverifikasi bahwa skenario tertentu tidak menerima keberhasilan respon json jadi saya memiliki baris berikut:

controller.should_receive(:render).with(hash_including(:success => true))

Meskipun ketika saya menjalankan tes saya saya mendapatkan error berikut:

Failure/Error: controller.should_receive(:render).with(hash_including(:success => false))
 (#<AnnoController:0x00000002de0560>).render(hash_including(:success=>false))
     expected: 1 time
     received: 0 times

Aku memeriksa respon yang salah?

Larutan

Anda dapat memeriksa respon objek dan memverifikasi bahwa itu mengandung nilai yang diharapkan:

@expected = { 
        :flashcard  => @flashcard,
        :lesson     => @lesson,
        :success    => true
}.to_json
get :action # replace with action name / params as necessary
response.body.should == @expected

EDIT

Perubahan ini untuk post membuatnya sedikit lebih sulit. Berikut ini's cara untuk mengatasinya:

 it "responds with JSON" do
    my_model = stub_model(MyModel,:save=>true)
    MyModel.stub(:new).with({'these' => 'params'}) { my_model }
    post :create, :my_model => {'these' => 'params'}, :format => :json
    response.body.should == my_model.to_json
  end

Perhatikan bahwa mock_model tidak akan menanggapi to_json, jadi stub_model atau model nyata contoh yang dibutuhkan.

Komentar (7)

Anda bisa mengurai respon tubuh seperti ini:

parsed_body = JSON.parse(response.body)

Kemudian anda dapat membuat anda terhadap pernyataan yang diuraikan konten.

parsed_body["foo"].should == "bar"
Komentar (7)

Membangun off dari Kevin Trowbridge's jawaban

response.header['Content-Type'].should include 'application/json'
Komentar (3)

Ada's juga json_spec gem, yang layak lihat

https://github.com/collectiveidea/json_spec

Komentar (1)

Sederhana dan mudah cara untuk melakukan hal ini.

# set some variable on success like :success => true in your controller
controller.rb
render :json => {:success => true, :data => data} # on success

spec_controller.rb
parse_json = JSON(response.body)
parse_json["success"].should == true
Komentar (1)

Anda juga dapat mendefinisikan fungsi helper dalam spec/support/

module ApiHelpers
  def json_body
    JSON.parse(response.body)
  end
end

RSpec.configure do |config| 
  config.include ApiHelpers, type: :request
end

dan menggunakan json_body setiap kali anda perlu untuk mengakses respon JSON.

Misalnya, dalam permintaan spec anda dapat menggunakannya langsung

context 'when the request contains an authentication header' do
  it 'should return the user info' do
    user  = create(:user)
    get URL, headers: authenticated_header(user)

    expect(response).to have_http_status(:ok)
    expect(response.content_type).to eq('application/vnd.api+json')
    expect(json_body["data"]["attributes"]["email"]).to eq(user.email)
    expect(json_body["data"]["attributes"]["name"]).to eq(user.name)
  end
end
Komentar (0)

Pendekatan lain untuk menguji hanya untuk respon JSON (tidak bahwa konten yang hanya berisi sebuah nilai yang diharapkan), adalah untuk mengurai respon menggunakan ActiveSupport:

ActiveSupport::JSON.decode(response.body).should_not be_nil

Jika respon tidak dapat diuraikan JSON exception akan dilempar dan tes akan gagal.

Komentar (0)

Anda bisa melihat ke &#39;Content-Type&#39; header untuk melihat bahwa itu adalah benar?

response.header['Content-Type'].should include 'text/javascript'
Komentar (3)

Ketika menggunakan Rel 5 (saat ini masih dalam versi beta), ada's metode baru, parsed_body pada tes respon, yang akan mengembalikan respon diuraikan sebagai apa permintaan terakhir adalah dikodekan pada.

Komit pada GitHub: https://github.com/rails/rails/commit/eee3534b

Komentar (1)

Jika anda ingin mengambil keuntungan dari hash diff Rspec menyediakan, itu lebih baik untuk mengurai tubuh dan membandingkan terhadap hash. Cara paling sederhana I've ditemukan:

it 'asserts json body' do
  expected_body = {
    my: 'json',
    hash: 'ok'
  }.stringify_keys

  expect(JSON.parse(response.body)).to eql(expected_body)
end
Komentar (0)

Saya menemukan pelanggan matcher di sini: https://raw.github.com/gist/917903/92d7101f643e07896659f84609c117c4c279dfad/have_content_type.rb

Meletakkannya di spec/dukungan/pencocokan/have_content_type.rb dan pastikan untuk memuat barang-barang dari dukungan dengan sesuatu seperti ini di dalam kamu spec/spec_helper.rb

Dir[Rails.root.join('spec/support/**/*.rb')].each {|f| require f}

Berikut ini adalah kode itu sendiri, hanya dalam kasus itu menghilang dari link yang diberikan.

RSpec::Matchers.define :have_content_type do |content_type|
  CONTENT_HEADER_MATCHER = /^(.*?)(?:; charset=(.*))?$/

  chain :with_charset do |charset|
    @charset = charset
  end

  match do |response|
    _, content, charset = *content_type_header.match(CONTENT_HEADER_MATCHER).to_a

    if @charset
      @charset == charset && content == content_type
    else
      content == content_type
    end
  end

  failure_message_for_should do |response|
    if @charset
      "Content type #{content_type_header.inspect} should match #{content_type.inspect} with charset #{@charset}"
    else
      "Content type #{content_type_header.inspect} should match #{content_type.inspect}"
    end
  end

  failure_message_for_should_not do |model|
    if @charset
      "Content type #{content_type_header.inspect} should not match #{content_type.inspect} with charset #{@charset}"
    else
      "Content type #{content_type_header.inspect} should not match #{content_type.inspect}"
    end
  end

  def content_type_header
    response.headers['Content-Type']
  end
end
Komentar (0)