복붙노트

[RUBY-ON-RAILS] 어떻게 RSpec에를 사용하여 JSON 응답을 확인하는?

RUBY-ON-RAILS

어떻게 RSpec에를 사용하여 JSON 응답을 확인하는?

나는 내 컨트롤러에 다음 코드를 :

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

내 RSpec에 컨트롤러 테스트에서 나는 어떤 시나리오가 나는 다음과 같은 라인을했다, 그래서 성공 json으로 응답을받지 않는다는 것을 확인하려면 :

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

내 테스트를 실행할 때 있지만 나는 다음과 같은 오류가 발생합니다 :

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

내가 잘못 응답을 확인하는 건가요?

해결법

  1. ==============================

    1.당신은 응답 객체를 검토하고 예상 값이 포함되어 있는지 확인할 수 있습니다 :

    당신은 응답 객체를 검토하고 예상 값이 포함되어 있는지 확인할 수 있습니다 :

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

    편집하다

    게시물이를 변경하면 조금 난이도가 있습니다. 여기를 처리하는 방법이있다 :

     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
    

    하나 stub_model 또는 실제 모델 인스턴스가 필요하므로 mock_model이 to_json에 응답하지 않습니다.

  2. ==============================

    2.이 같은 응답 본문을 구문 분석 할 수 있습니다 :

    이 같은 응답 본문을 구문 분석 할 수 있습니다 :

    parsed_body = JSON.parse(response.body)
    

    그럼 당신은 그 구문 분석 된 내용에 대하여 당신의 주장을 할 수 있습니다.

    parsed_body["foo"].should == "bar"
    
  3. ==============================

    3.케빈 트로 브리지의 대답의 오프 구축

    케빈 트로 브리지의 대답의 오프 구축

    response.header['Content-Type'].should include 'application/json'
    
  4. ==============================

    4.가치의 모습입니다 json_spec 보석도있다

    가치의 모습입니다 json_spec 보석도있다

    https://github.com/collectiveidea/json_spec

  5. ==============================

    5.방법을 간단하고 쉽게이 작업을 수행합니다.

    방법을 간단하고 쉽게이 작업을 수행합니다.

    # 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
    
  6. ==============================

    6.또한 사양 / 지원 내부 도우미 함수를 정의 할 수 있습니다 /

    또한 사양 / 지원 내부 도우미 함수를 정의 할 수 있습니다 /

    module ApiHelpers
      def json_body
        JSON.parse(response.body)
      end
    end
    
    RSpec.configure do |config| 
      config.include ApiHelpers, type: :request
    end
    

    당신은 JSON 응답에 액세스해야 할 때마다 사용 json_body.

    예를 들어, 귀하의 요청 내부에 직접 사용할 수 있습니다 스펙

    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
    
  7. ==============================

    7.단지 JSON 응답을 테스트하는 또 다른 방법 (안 예상 값을 포함 내에서 내용이 있음), ActiveSupport를 사용하여 응답을 구문 분석하는 것입니다 :

    단지 JSON 응답을 테스트하는 또 다른 방법 (안 예상 값을 포함 내에서 내용이 있음), ActiveSupport를 사용하여 응답을 구문 분석하는 것입니다 :

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

    응답이 JSON 구문 분석하지 않으면 예외가 발생하고 테스트가 실패합니다.

  8. ==============================

    8.당신은이 올바른지 확인하기 위해 '콘텐츠 유형'헤더로 볼 수 있을까?

    당신은이 올바른지 확인하기 위해 '콘텐츠 유형'헤더로 볼 수 있을까?

    response.header['Content-Type'].should include 'text/javascript'
    
  9. ==============================

    9.(현재 베타 여전히) 레일 (5)를 사용하는 경우, 마지막 요청은 인코딩 된 것을로 분석 응답을 반환하는 새로운 방법, 시험 응답에 parsed_body,있다.

    (현재 베타 여전히) 레일 (5)를 사용하는 경우, 마지막 요청은 인코딩 된 것을로 분석 응답을 반환하는 새로운 방법, 시험 응답에 parsed_body,있다.

    (가) GitHub에 커밋 : https://github.com/rails/rails/commit/eee3534b

  10. ==============================

    10.당신이 RSpec에 제공하는 해시 DIFF을 활용하고자하는 경우에는 몸을 구문 분석하고 해시와 비교하는 것이 좋습니다. 가장 간단한 방법 I의 한 발견 :

    당신이 RSpec에 제공하는 해시 DIFF을 활용하고자하는 경우에는 몸을 구문 분석하고 해시와 비교하는 것이 좋습니다. 가장 간단한 방법 I의 한 발견 :

    it 'asserts json body' do
      expected_body = {
        my: 'json',
        hash: 'ok'
      }.stringify_keys
    
      expect(JSON.parse(response.body)).to eql(expected_body)
    end
    
  11. ==============================

    11.내가 여기에 고객 정규 발견 : https://raw.github.com/gist/917903/92d7101f643e07896659f84609c117c4c279dfad/have_content_type.rb

    내가 여기에 고객 정규 발견 : https://raw.github.com/gist/917903/92d7101f643e07896659f84609c117c4c279dfad/have_content_type.rb

    당신 사양 / spec_helper.rb에서이 같은과 지원에서 부하 물건에 있는지 사양 / 지원 / 정합 기 / have_content_type.rb에 넣어 및 확인

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

    여기 주어진 링크에서 사라 단지의 경우 코드 자체입니다.

    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
    
  12. ==============================

    12.이 RSpec에의 최신 버전 (3.8+)에 대한 빠른 요약 그래서 위의 답변의 많은, 구식 조금 있습니다. 이 솔루션은 rubocop-RSpec에로부터 경고를 제기하지 않고 RSpec에 모범 사례 인라인입니다 :

    이 RSpec에의 최신 버전 (3.8+)에 대한 빠른 요약 그래서 위의 답변의 많은, 구식 조금 있습니다. 이 솔루션은 rubocop-RSpec에로부터 경고를 제기하지 않고 RSpec에 모범 사례 인라인입니다 :

    성공적인 JSON 응답은 두 가지로 식별됩니다 :

    응답 객체가 시험의 익명 될 수 있다고 가정하면, 위의 두 조건이 모두는 RSpec에의 매처 (matcher)에 내장을 사용하여 검증 할 수 있습니다 :

    context 'when response is received' do
      subject { response }
    
      # check for a successful JSON response
      it { is_expected.to have_attributes(content_type: include('application/json')) }
      it { is_expected.to have_attributes(body: satisfy { |v| JSON.parse(v) }) }
    
      # validates OP's condition
      it { is_expected.to satisfy { |v| JSON.parse(v.body).key?('success') }
      it { is_expected.to satisfy { |v| JSON.parse(v.body)['success'] == true }
    end
    

    당신이 다음 피사체의 이름을 준비하는 경우 위의 테스트는 더욱 단순화 할 수있다 :

    context 'when response is received' do
      subject(:response) { response }
    
      it 'responds with a valid content type' do
        expect(response.content_type).to include('application/json')
      end
    
      it 'responds with a valid json object' do
        expect { JSON.parse(response.body) }.not_to raise_error
      end
    
      it 'validates OPs condition' do
        expect(JSON.parse(response.body, symoblize_names: true))
          .to include(success: true)
      end
    end
    
  13. ==============================

    13.깨끗한하지만 잠재적으로 큰 DIFF는 산출 :

    깨끗한하지만 잠재적으로 큰 DIFF는 산출 :

    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으로 언급하는)

    당신이 철 - 클래드 솔루션을 원한다면, 당신은 거짓 양성 평등을 소개 할 수 파서를 사용하지 않아야합니다; 문자열에 대한 응답 본문을 비교합니다. 예컨대 :

    actual = response.body
    expected = ({ foo: "bar" }).to_json
    expect(actual).to eq expected
    

    그러나이 두 번째 솔루션은 적은 시각적 친화적가 탈출 따옴표를 많이 포함 할 것이다 직렬화 된 JSON을 사용하기 때문에입니다.

    나 자신에게 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
    

    사용 일의 예 :

    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를 해결하는 방법을 알려줍니다.

  14. from https://stackoverflow.com/questions/5159882/how-to-check-for-a-json-response-using-rspec by cc-by-sa and MIT license