Testy testom nierówne?

W skrócie, pogubiłem się lekko co jest mi potrzebne do testowania aplikacji: cucumber + unit testy wystarczą (i odpalać je sobie autotestem?). Pisanie aplikacji powinienem zacząć od stworzenia kilku scenariuszy w cucumberze?

My w firmie nie uzywaliśmy cucumbera, teraz tworzy się dopiero pierwszy projekt z jego użyciem (ale nie dlatego, że wcześniej robiliśmy coś źle). W dwóch projektach korzystamy z shouldy. W pozostaly stary dobry Test::Unit. IMO niej est ważne w czym piszesz swoje testy, ważne byś je wogóle pisał. Dobrym miernikiem według mnie też jest test coverage wykonywane za pomocą rcov’a. Pokazuje Ci, które części twojego kodu nie były przetestowane.

Cucumber + Test::Unit powinny wystarczyć w zupełności, chociaż pobaw się też RSpec’iem (ale ja niestety coraz mniej go lubię).

Tomash czemu coraz mneij?

Dwa słowa: mocki i stuby.
Jak używasz sporo np. named scope’ów (albo ogólnie sporo funkcji i makr), stubowanie każdego po kolei zamienia się w koszmarek.
Ewentualnie RSpec z klasycznymi fixturami daje radę, ale wtedy ma niewielką przewagę nad klasycznym Test::Unit.

Ja używam RSpec + factory girl i nie staram się wszystkiego stubować i mockować, bo to rzeczywiście strasznie uciążliwe. Jak od czasu do czasu się dotknie bazy danych, to nic się nie stanie :wink:

Ale ja w testach nie czuję się jeszcze najmocniejszy, więc mogę nie mieć racji :slight_smile:

Osobiscie jestem za cucumberem + rspec(bez stubow i mockow) z factory girl

Jeśli pozwolicie, chciałbym wrócić do starego tematu.
Czy mógłby ktoś pokrótce scharakteryzować to, o czym piszecie?
Mam na myśli:

Test::Unit,
RSpec,
Shoulda,
Cucumber,
Factory Girl,
Webrat.

Nie chodzi mi o to, co można przeczytać na stronach projektów, czy w oficjalnych dokumentacjach, ale może w ten sposób: w jaki sposób dobrać właściwe rozwiązanie do testów i ewentualnie jakie kryteria określające naszą planowaną aplikację należy brać pod uwagę wybierając to rozwiązanie? Albo jeszcze inaczej: co najmniej zaboli Javusa przyzwyczajonego do JUnita?

Do testów jednostkowych(np. modele) i funkcjonalnych(np. kontrolery) wybierz sobie jedno z tych narzędzi

  • Test::Unit
  • RSpec
  • Shoulda
    Test::Unit to standardowy framework do testowania w railsach. Dużo lepszym rozwiązaniem jest albo Rspec albo nakładka na Test::Unit Shoulda. Oba frameworki mają dużo więcej przydatnych możliwości. Z tych dwóch wybierz ten, który ładniej dla ciebie wygląda. Ja wolę Shoulda :slight_smile:

Do testów integracyjnych najlepiej użyć Cucumbera + webrata do komunikacji z naszą aplikacją. Cucumber + webrat do obsługi to taki standardowy zestaw. Najlepiej zobacz tego screencasta to będziesz wiedzieć o co chodzi dokładnie: http://railscasts.com/episodes/155-beginning-with-cucumber

Factory girl to tak zwana fabryka do testów. Dostarcza Ci ona wiele prostych metod do tworzenia danych używanych w testach. Jeśli w testach będziesz chciał stworzyć np. kilku użytkowników o różnych parametrach, to Fabryka ułatwi Ci tutaj pracę. Działa to podobnie jak railsowe Fixtures, ale daje dużo większe możlwiości. Osobiście nie przepadam za Factory Girl i wolę używać Machinist’a : http://github.com/notahat/machinist

Jakbym zaczynał teraz nowy projekt to użyłbym Shoulda + Cucumber z webratem + Machinist + Pickle(pomoc do cucumbera: http://github.com/ianwhite/pickle )

Uch, nie. Służy podobnemu celowi, ale działa zupełnie inaczej. Między innymi podchodzi pod pełny cykl życia obiektu (walidacje i callbacki), w przeciwieństwie do fixtur.

Co do reszty posta Staszka to +1, lepiej bym tego nie ujął. :slight_smile:

Uch, nie. Służy podobnemu celowi, ale działa zupełnie inaczej. Między innymi podchodzi pod pełny cykl życia obiektu (walidacje i callbacki), w przeciwieństwie do fixtur.[/quote]
Racja, źle to ująłem:) Najlepiej zobaczyć jakiś przykład to będzie dokładnie wiadomo o co chodzi

Dzięki, Staszku! Dokładnie o takie podsumowanie mi chodziło! Genialnie, biorę się od razu do roboty.

Ja tylko mogę dodać, że webrat nie jest obecnie najlepszym rozwiązaniem do testów funkcjonalnych. Jeżeli masz zainstalowanego najnowszego cucumbera, to przy generowaniu plików dla railsów można wybrać capybarę używając przełącznika --capybara.

I teraz krótko o tym dlaczego capybara jest moim skromnym zdaniem lepsza od webrata. Webrat powstał jako nakładka na railsowe testy integracyjne. Później dopisane zostały dodatkowe tryby do selenium i mechanize. Brzmi fajnie, ale implementacja nie jest doskonała, prawdopodobnie ze względu na to, że kod nie był projektowany do pracy z czymkolwiek innym niż testy integracyjne railsow. Prowadzi to do tego, że ciężko jest napisać kod, który będzie działał w każdym z trybów. Capybara podchodzi do problemu trochę inaczej i pozostawiając bardzo podobne API już w tym momencie obsługuje rack-test, selenium, celerity i culerity.

Dla wyjaśnienia dodam, że tryb rack-test jest odpowiednikiem :rails w webracie. Jest to nakładka na rack-test - rozwiązanie najszybsze, ale bez możliwości wykonania javascripta.

Capybara ma dużo mniejsze niż webrat problemy z kompatybilnością pomiędzy różnymi narzędziami. Coś co mi się podoba najbardziej, to tłumaczenie selectorów css na xpath. Dzięki temu wszystkie narzędzia, które nie obsługują cssa (celerity, watir) mogą dalej być obsługiwane tymi samymi metodami. Dodatkowym ułatwieniem jest przygotowanie zestawu tagów cucumbera. Domyślnie scenariusze uruchamiają się w najszybszym trybie rack-test. Przy użyciu taga @javascript scenariusz zostaje uruchomiony w zdefiniowanym do javascriptu narzędziu (ustawić to można pisząc na przykład Capybara.javascript_driver = :celerity). Dodatkowo można używać również tagów wybierających konkretne narzędzie: @selenium, @celerity, @culerity, @rack.

Jeżeli chodzi o javascript, to dużym ułatwieniem jest też fakt, że każdy z kroków czeka na pojawienie się wymaganego elementu. Np. ‘Then I should see “foo” within “#search_results”’ poczeka aż w elemencie #search_results pojawi się tekst “foo” (albo aż miną 2 sekundy, wtedy dosatniemy timeout error. a te 2s można oczywiście dowolnie zmienić). W większości przypadków rozwiązuje to wszelkie problemy z ajaxem i ogólnie javascriptem.

Czy można tego używać bez strachu? Przepisałem ostatnio test suite liczący ok. 80 scenariuszy, wcześniej napisany w culerity. Działa bardzo fajnie, na razie nie napotkałem żadnych problemów. W tej chwili testy z javascriptami odpalam w trybie selenium, ale na pewno w najbliższym czasie sprawdzę też culerity.

Na pewno jest to bardzo fajne rozwiązanie dla ludzi, którzy do tej pory korzystali z culerity. Jak wszyscy wiemy culerity w niektórych miejscach nie daje rady z javascriptami i wtedy przydaje się odpalić testy w przeglądarce. Dzięki temu możemy mieć test suite, w którym:

  • większość testów uruchamia się w trybie rack-test
  • proste javascripty uruchamiają się w celerity/culerity
  • wszystko to z czym nie daje sobie rady celerity odpalamy w selenium

Jest to najlepszy kompromis pomiędzy szybkością, a kompatybilnością testów z rzeczywistością.

Przy okazji, przepisanie takiego test suitu wcale nie trwa tak długo. Podstawowe kroki używane przez webrata, takie jak “When 'I fill in ‘password’ with ‘secret’” są już zdefiniowane, więc duża część scenariuszy przechodzi od razu.

[quote=Tomash]Dwa słowa: mocki i stuby.
Jak używasz sporo np. named scope’ów (albo ogólnie sporo funkcji i makr), stubowanie każdego po kolei zamienia się w koszmarek.
Ewentualnie RSpec z klasycznymi fixturami daje radę, ale wtedy ma niewielką przewagę nad klasycznym Test::Unit.[/quote]
A jak testujesz named scope w Test::Unit?
Rozumiem, że do generowania danych używasz Factory Girl?

[quote=slawosz][quote=Tomash]Dwa słowa: mocki i stuby.
Jak używasz sporo np. named scope’ów (albo ogólnie sporo funkcji i makr), stubowanie każdego po kolei zamienia się w koszmarek.
Ewentualnie RSpec z klasycznymi fixturami daje radę, ale wtedy ma niewielką przewagę nad klasycznym Test::Unit.[/quote]
A jak testujesz named scope w Test::Unit?
Rozumiem, że do generowania danych używasz Factory Girl?[/quote]
Poszukaj posta o testowaniu named_scope na Giants Robots Smashing Into Other Giant Robots (uwielbiam tą nazwę swoją drogą). Ogólnie idea jest taka, żeby named_scope’ów nie testować, ale też nie używać w kontrolerach i widokach. Tzn. żeby named_scope’y zamykać w metody klasy. Dla mnie to jest fajne wyjście, bo od kiedy są named scope’y, widzę coraz więcej bajzlu w kontrolerach (także w swoich :wink: ).

Dawno nie czytałem tyle zła w jednym zdaniu.

Przyznaję się, że w praktyce tego często nie stosuję jak na razie, ale dalej wydaje mi się to niezłą zasadą. A jeżeli nie, to może w drugą stronę, dla skupienia uwagi wrzućmy linijkę w tym stylu w kontrolerze:

@articles = Article.public.active.order("created_at DESC").joins([:comments, :user, :images]).all.paginate(:per_page => 10, :page => params[:page])

Wrzuć mi mocki/stuby do takiego kontrolera. Zakładając, że chcesz przetestować coś co w cucumberze przetestować jest ciężko (na przykład sytuacja, która nie może wystąpić w wyniku interakcji z UI, ale jakiś zły człowiek może wziąć curla i nam coś popsuć).

Więcej info tutaj o dostępnych opcjach tutaj: http://robots.thoughtbot.com/post/200254501/testing-named-scopes

Dzięki za pomoc, po weekendzie, poczytam i potestuję :slight_smile:

@Tomash:
Mógłbyś napisać jak Ty podchodzisz do testowania name scopów, albo nawet do testowania ogólnie?

[quote=Tomash]Dwa słowa: mocki i stuby.
Jak używasz sporo np. named scope’ów (albo ogólnie sporo funkcji i makr), stubowanie każdego po kolei zamienia się w koszmarek.[/quote]
Co rozumiesz poprzez funkcje i makra?

Wrzucę swoje 3 grosze.

Moim zdaniem najlepsze jest takie podejście:

  1. Piszesz kilka scenariuszy w Cucumberze, ale zostawiasz implementację poszczególnych kroków na później.
  2. Piszesz testy dla modeli w RSpec albo Unit::Test.
  3. Implementujesz algorytmy które wcześniej opisałeś w cucumberze i RSecu, doprowadzając testy RSpec do koloru zielonego.
  4. Implementujesz kroki Cucumbera (step definitions) i wszystko co jest potrzebne na poziomie widoków i kontrolerów aby świeciły się na zielono XD.

Dlaczego taka kolejność i dlaczego ten cykl jest bardzo ważny? Po pierwsze, zmusza Cię do pomyślenia o zadaniu od strony użytkownika końcowego (krok 1). Po drugie, szybko przechodzisz do implementowania logiki i algorytmów (krok 2), więc na potencjalne problemy natrafiasz szybciej. Może Cię to czasem skłonić do zmiany założeń pierwotnych i wprowadzenia zmian nawet w scenariuszach Cucumbera.

[quote=hubertlepicki]Wrzucę swoje 3 grosze.

Moim zdaniem najlepsze jest takie podejście:

  1. Piszesz kilka scenariuszy w Cucumberze, ale zostawiasz implementację poszczególnych kroków na później.
  2. Piszesz testy dla modeli w RSpec albo Unit::Test.
  3. Implementujesz algorytmy które wcześniej opisałeś w cucumberze i RSecu, doprowadzając testy RSpec do koloru zielonego.
  4. Implementujesz kroki Cucumbera (step definitions) i wszystko co jest potrzebne na poziomie widoków i kontrolerów aby świeciły się na zielono XD.

Dlaczego taka kolejność i dlaczego ten cykl jest bardzo ważny? Po pierwsze, zmusza Cię do pomyślenia o zadaniu od strony użytkownika końcowego (krok 1). Po drugie, szybko przechodzisz do implementowania logiki i algorytmów (krok 2), więc na potencjalne problemy natrafiasz szybciej. Może Cię to czasem skłonić do zmiany założeń pierwotnych i wprowadzenia zmian nawet w scenariuszach Cucumbera.[/quote]
Właśnie opisałeś cykl developmentu sugerowany przez “The RSpec Book Behaviour Driven Development with RSpec, Cucumber, and Friends” :wink: