2011-11-26 12 views
22

To moje działanie:Jak przeprowadzić test jednostkowy kontrolera JSON?

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

To moja próba:

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

Chcę dodać kolejne twierdzenie, że emitowane JSON zawiera jakąś wartość. Jak mogę to zrobić w jednostce kontrolnej, a nie poprzez analizowanie wyniku widoku?

+1

Czy parsowanie odpowiedzi jsona nie byłoby najprostszym sposobem? – jdeseno

+0

Miałem wrażenie, że testy jednostkowe faktycznie nie wywołują widoku. Czy tak jest? Jeśli tak, jakiego rodzaju test jest tym, czego szukam (widok?) –

+1

Wierzę, że to pytanie zostało już omówione [tutaj] (http://stackoverflow.com/questions/336716/how-to-test-json-result-from -chałki-testy funkcjonalne). To, co robisz, nie jest jednostką, ale testem funkcjonalnym. I faktycznie renderuje widok. –

Odpowiedz

43

Tak jak ludzie komentowali powyżej, byłby to test funkcjonalny.

Najlepszym sposobem byłaby prawdopodobnie prośba, parsowanie treści odpowiedzi JSON i dopasowanie jej do oczekiwanego wyniku.

Jeśli mam companies_controller w rspec użyciu FactoryGirl:

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 

można przetestować inne atrybuty w ten sam sposób. Ponadto zwykle mam kontekst invalid, w którym spróbuję przekazać nieprawidłowe parametry.

+0

Czy FactoryGirl nie wymaga modelu, więc w twoim przykładzie musisz mieć model dla "firmy"? – Ninja

+0

Uratowałeś mojego człowieka. wielkie dzięki. – Abhinay

15

pomocą wbudowanego testu funkcjonalnego szyn:

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

Działa to, gdy masz funkcję respond_to, która zwraca różne dane w oparciu o różne bloki. W powyższym przykładzie plakat określa metodę, w jakiej ŻĄDANIE jest wysyłane do kontrolera, aby wywołać właściwy blok respond_to. – FlyingV

3

Moje podejście do tego jest nieco inna, jeśli używam Jbuilder klejnot, który jest teraz dostępny z zespołem szyn. (To podejście odnosi się do innych klejnotów, które renderują lub jako widoki.) Preferuję testy jednostkowe w testach funkcjonalnych, gdy tylko jest to możliwe, ponieważ mogą być one trochę szybsze. Dzięki JBolderowi większość testów można przekształcić w testy jednostkowe.

Tak, nadal masz testy funkcjonalne na kontrolerze, ale jest ich bardzo niewiele i nie analizują JSON. Test funkcjonalny testuje wyłącznie logikę sterownika, a nie renderowany JSON. Funkcjonalny test ważnego wniosku może dochodzić następujące (rspec):

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

Ja tylko sprawdzenie, czy to się powiedzie, to sprawia, że ​​szablon, a przechodzi element do szablonu. W tym momencie widok zawiera informacje potrzebne do prawidłowego renderowania.

Teraz przetestuj JSON renderowany przez jednostkę testując widok JBoader.

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

Test ten kontroler działa dobrze dla mnie za pomocą MiniTest z Rails 4.2.4:

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 

I to działało w formie testu integracyjnego.

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 

Szczerze mówiąc, to dziwne, starając się zachować syntaktyczne niuanse prosto z jednego rodzaju testu na inny.

Powiązane problemy