2011-11-26 15 views
22

Questa è la mia azione:Come testare unitamente un controller JSON?

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

Questa è la mia prova:

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

voglio aggiungere un'altra affermazione che il JSON emessa contiene un certo valore. Come posso farlo in un test dell'unità di controllo, non tramite l'analisi del risultato della vista?

+1

Non analizzando la risposta JSON essere il modo più semplice? – jdeseno

+0

Avevo l'impressione che i test unitari non richiamassero effettivamente la vista. È il caso? Se sì quale tipo di test è quello che cerco (vedi?) –

+1

Credo che questa domanda sia già stata discussa [qui] (http://stackoverflow.com/questions/336716/how-to-test-json-result-from -rails-funzionali-test). Quello che stai facendo non è unità, ma test funzionale. E rende effettivamente la vista. –

risposta

43

Proprio come le persone hanno commentato sopra, questo sarebbe un test funzionale.

Il modo migliore sarebbe probabilmente effettuare una richiesta, analizzare il corpo della risposta JSON e farlo corrispondere al risultato previsto.

Se ho companies_controller in Rspec utilizzando 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 

È possibile provare altri attributi allo stesso modo. Inoltre, ho normalmente il contesto invalid in cui proverei a passare i parametri non validi.

+0

Non FactoryGirl richiede un modello, quindi nel tuo esempio devi avere un modello per "azienda"? – Ninja

+0

Hai salvato il mio uomo giorno. molte grazie. – Abhinay

15

Utilizzando test funzionale built-in Rails':

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

Funziona quando si ha una funzione respond_to che restituisce dati diversi in base ai diversi blocchi. Nell'esempio sopra, il poster definisce il metodo con cui viene inviata la REQUEST al controller, per attivare il blocco response_to corretto. – FlyingV

3

Il mio approccio a questo è leggermente diverso se sto usando la gemma Jbuilder che ora è disponibile dal team di Rails. (Questo approccio si applica ad altre gemme che rendono JSON o XML come viste.) Preferisco test unitari sui test funzionali quando possibile, dal momento che possono essere un po 'più veloci. Con Jbuilder puoi trasformare la maggior parte dei test in test unitari.

Sì, sono ancora disponibili test funzionali sul controller, ma ce ne sono pochissimi e non analizzano il JSON. Il test funzionale verifica esclusivamente la logica del controller, non il JSON renderizzato. Un test funzionale per una richiesta valida potrebbe affermare il seguente (RSpec):

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

Sto solo verificando che è successo, rende il modello, e passa l'oggetto al modello. A questo punto, la vista ha le informazioni necessarie per eseguire il rendering corretto.

Ora testare il JSON renderizzato dall'unità testando la vista di Jbuilder.

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

Questo test di controllo ha funzionato bene per me usando Minitest con 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 

E questo ha funzionato nella forma di un test di integrazione.

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 

Onestamente, è strano cercando di mantenere le sfumature sintattiche direttamente da un tipo di prova ad un altro.

Problemi correlati