Rspec - testowanie controllera

Cześć, ogarniam Rspec Book i przy testowaniu controllera mam kilka pytań.
mam model Ad name:string title:string price:integer … stworzony został przez scaffold

[code=ruby]# spec/controllers/ad_controller_spec.rb
require ‘spec_helper’

describe AdsController do
before do
@ad = mock_model(Ad, :save => true)
Ad.stub!(:new).and_return(@ad)
#@params = {}
end

def do_post
	post :create,
           #:ad => @params
end

describe "#create" do
	it "creates a new ad" do
		Ad.should_receive(:new).
                    #with(@params).
                   and_return(@ad)
		do_post
	end

	it "save a new ad" do
	end

    it "redirects to Ad index" do
	post :create
	response.should redirect_to(:action => "index")
end

end
end[/code]
Takie testy napisałem do tej pory, wszystkie przeszły.

  1. Nie wiem narazie jak napisać test sprawdzający czy ogłoszenie zostało zapisane.
  2. Czy przy testowaniu kontrolera stosujecie jeszcze jakieś inne testy?
  3. Rozumiem, że mock_model tworzy mi Ad z wypełnionymi wszystkimi polami i nie muszę tego robić ręcznie.
  4. Co jednak robi stub!? i część and_return
  5. Wyhaszowałem część, którą znalazłem w którymś tutorialu dotyczącą #params, testy przechodzą z nią i bez niej, mógłby mi ktoś wytłumaczyć za co ona odpowiada?

Testuje ktoś w ogóle kontrolery?

Czy tylko zawszę testy unitowe oraz integracyjne?

PS Na Railscastsach Ryan polecał powyższe kombo
http://railscasts.com/episodes/275-how-i-test

“1. Nie wiem narazie jak napisać test sprawdzający czy ogłoszenie zostało zapisane.”

Najłatwiej sprawdzić to poprzez sprawdzenie czy zwiększyła się liczba:

it "should save a new ad" do lambda do post :create end.should change(Ad, :count).by(1) end
“5. Wyhaszowałem część, którą znalazłem w którymś tutorialu dotyczącą #params, testy przechodzą z nią i bez niej, mógłby mi ktoś wytłumaczyć za co ona odpowiada?”

Zmienną @params masz pustą, więc nic dziwnego, że testy przechodzą poprawnie z nią i bez niej :wink:
Przekazujesz to co normalnie dostajesz w GET czy POST z formularza.

Funkcja kontrela nie jest zapisanie ogłoszenia tylko wysłanie rzadania zapisania gdzies indziej. Teraz testujesz czy Ad wykouje metedę new z paramaterami z params. Możesz jeszcze dodac sprawdzanie czy utworzony obiekt otrzymuje motode save (przed do_post w describe “#create”):

@ad.should_receive(:save).and_return(true)

generalnie testujsz to co robi kontroler. Np redirecty, pzypisywanie zmiennych dla widoku, czy wykonuja sie filtry, ograniczanie dostepu jesli jest itp.

Nie, mock_model tworzy mock’a ze stub’ami na niektórych motodach ActiveRecord’a. stub_model tworzy instancje twojego obiektu ze stub’ami na niektórych motodach ActiveRecord’a. Jeśli chcesz mieć instancje obiektu z powypelnianymi polami mozesz uzyc Factory Girl, Machinist albo Fabrication.

stub dodaje metode to obiektu, and_return określa co stub (albo exceptation) zwraca. Np:

Ad.stub!(:new).and_return(@ad)

Spowoduje ze każde wywolanie Ad.new zwróci @ad, ale nic sie nie stanie jesli podczas testu nie bedzie wywolania Ad.new

Ad.should_receive(:new).with({}).and_return(@ad)

Na Ad powinna byc wykonana metoda new z parametrem {} i zwróci @ad

Ad.should_receive(:new).and_return(@ad)

Na Ad powinna byc wykonana metoda new (z dowolnymi parametrami lub bez) i zwróci @ad

Wykomentuwując wszystkie odwołania do @params testujesz bardziej obolny scenariusz.

Tak.

Nie wiem co masz na myśli pod pojęciem „testy integracyjne”, ale założę, że chodzi Ci o to co ja rozumiem pod „akceptacyjne”, np. cucumber, czy inne capybara-webkit, etc. One są po prostu wolniejsze niż testy kontrolerów i nie ma sensu ich używać do testowania wszystkich możliwych zachowań kontrolera.

Ja szczerze mówiąc testuję kontrolery głównie w przypadku kiedy mają jakieś niestandardowe rzeczy, które chcę sprawdzić (np. czy cookie się ustawiło). Ostatnio nie pisałem żadnej aplikacji z rozbudowanym systemem uprawnień, ale w takim przypadku też bym to zrobił jako testy kontrolerów. Jeżeli kontroler jest dosyć standardowy, tzn. najczęściej wywołanie jednej metody, to zostawiam to dla testów akceptacyjnych (chyba, że z jakiegoś powodu nie chcę pisać testów akceptacyjnych dla danego przypadku).

Tak. Kiedy udostępniasz API, izolowane testy kontrolerów to jest to.

(oczywiście do testowania doświadczenia klikającego usera, integracyjne są o wiele lepsze)