2011-11-26 21 views
22

これは私のアクションです:JSONコントローラの単体テスト方法は?

def my_action 
    str = ... # get json str somehow 
    render :json => str 
end 

これは私のテストです:

test "my test" do 
    post(:my_action, {'param' => "value"}  
    assert_response :success 
end 

私が放出されるJSONは、いくつかの値が含まれていることを別のアサーションを追加します。ビューの結果を解析するのではなく、コントローラのユニットテストでどのように行うことができますか?

+1

json応答を解析するのが最も簡単な方法でしょうか? – jdeseno

+0

私はユニットテストが実際にビューを呼び出さないという印象を受けました。それは事実ですか?はいの場合、どのような種類のテストを私が探しているもの(ビュー?) –

+1

私はこの質問は既に議論されていると信じている[ここ](http://stackoverflow.com/questions/336716/how-to-test-json-result-from -rails-functional-tests)である。あなたがやっているのはユニットではなく、機能テストです。実際にはビューがレンダリングされます。 –

答えて

43

上記のコメントのように、これは機能テストになります。

JSONレスポンス本体を解析して期待される結果と照合するのが最善の方法です。私はFactoryGirlを使用してRSpecの中でcompanies_controllerを持っている場合は

describe "GET 'show'" do 

    before(:each) do 
    @company = Factory(:company) 
    get 'show', :format => :json, :id => @company.id 
    end 

    it "should be successful" do 
    response.should be_success 
    end 

    it "should return the correct company when correct id is passed" do 
    body = JSON.parse(response.body) 
    body["id"].should == @company.id 
    end 

end 

あなたは同じように他の属性をテストすることができます。また、私は通常、無効なパラメータを渡そうとするコンテキストをinvalidとしています。 Railsの組み込みの機能テストを使用して

+0

FactoryGirlはモデルを必要としないので、あなたの例では、 "company"のモデルが必要ですか? – Ninja

+0

あなたは私の一日の人を救った。どうもありがとう。 – Abhinay

15

:私は今、Railsのチームから提供されていますJbuilder宝石を使用している場合は、これに

require 'test_helper' 

class ZombiesControllerTest < ActionController::TestCase 

    setup do 
    @request.headers['Accept'] = Mime::JSON 
    @request.headers['Content-Type'] = Mime::JSON.to_s 

    end 

    test "should post my action" do 
    post :my_action, { 'param' => "value" }, :format => "json" 
    assert_response :success 
    body = JSON.parse(response.body) 
    assert_equal "Some returned value", body["str"] 
    end 

end 
+0

これは、異なるブロックに基づいて異なるデータを返すrespond_to関数がある場合に機能します..上記の例では、ポスターはREQUESTがコントローラに送信され、正しいrespond_toブロックをトリガするメソッドを定義します。 – FlyingV

3

私のアプローチは少し異なります。 (このアプローチは、JSONまたはXMLをビューとしてレンダリングする他の宝石にも当てはまります)。私は、できるだけユニットテストを優先します。 Jbuilderを使用すると、ほとんどのテストを単体テストに変換できます。

はい、コントローラーの機能テストはまだありますが、ごくわずかであり、JSONを解析しません。機能テストは、レンダリングされたJSONではなくコントローラのロジックのみをテストします。有効な要求は、次のことを主張する可能性があるため、機能テスト(RSpecの):

assert_response :success 
    expect(response).to render_template(:show) 
    expect(assigns(:item).id).to eq(expected_item.id) 

私はちょうどそれが成功したことを確認していますが、それはテンプレートをレンダリングし、それがテンプレートにアイテムを渡します。この時点で、ビューには適切なレンダリングを行うために必要な情報があります。

JbuilderビューのユニットテストによってレンダリングされたJSONをテストします。

describe 'api/v1/items/show.json.jbuilder' do 
    it 'includes foo' do 
    assign(:item, account.build(foo: 'bar')) 

    render 

    json = JSON.parse(rendered) 
    expect(json['item']['foo']).to eq('bar') 
    end 

    # A bunch of other JSON tests... 
1

このコントローラーのテストでは、Railsの4.2.4でMinitestを使用して私のためによく働い:

require 'test_helper' 

class ThingsControllerTest < ActionController::TestCase 

    test "should successfully create a new thing" do 
    assert_difference 'Thing.count' do 
     @request.headers["Accept"] = "application/json" 

     post(:create, {thing: {name: "My Thing"}}) 
    end 

    assert_response :success 

    json_response = JSON.parse(@response.body) 
    assert_equal json_response["name"], "My Thing" 
    end 

end 

をそして、これは統合テストの形で働いていました。

require 'test_helper' 

class ThingsRequestsTest < ActionDispatch::IntegrationTest 

    test "creates new thing" do 
    assert_difference 'Thing.count' do 
     post("/things.json", {thing: { name: "My Thing"}}) 
    end 

    assert_equal 201, status 

    json_response = JSON.parse(@response.body) 
    assert_equal json_response["name"], "My Thing" 
    end 

end 

正直なところ、ある種のテストから別のテストに文法的なニュアンスをまっすぐに保つことは奇妙です。

関連する問題