Sinatra + Cucumber + Capybara
W piwnicy naszego biura znajduje się stół do Ping Ponga. Jakiś czas temu pojawił się pomysł, żeby zorganizować wewnętrzną ligę. Oczywiście nie ma mowy, żeby zapisywać punkty na kartce, zróbmy aplikację! Ponieważ będzie mało skomplikowana, to najlepiej w Sinatrze. Otestujmy ją ładnie i opiszmy na blogu.
Co powinna zawierać aplikacja:
- Banalnie prostą rejestrację i logowanie
- Możliwość dodawania rozgrywek
- Listę wyników
- Ranking
Z czego będziemy korzystać:
- Sinatra – bo co za dużo Railsów, to niezdrowo.
- Cucumber i Rspec – bo chcemy, żeby to było BDD.
- Capybara – bo bardzo dobrze zastępuje Webrata, a w sieci jest bardzo mało przykładów wykorzystania jej z Sinatrą
Dla kogo jest ten turorial:
- Dla osób, które chcą poznać Sinatrę.
- Dla osób, które nie znają BDD, cucumbera i jego ekosystemu.
- Dla tych, którzy znają jedno i drugie, ale są ciekawi jak to łatwo połączyć.
Zaczynamy
Zacznijmy od zainstalowania potrzebnych gemów. Na początek potrzebne nam będą:
gem install sinatra cucumber capybara rspec
Oprócz Sinatry
, potrzebujemy Cucumbera
, czyli narzędzia do uruchamiania testów integracyjnych, napisanych w języku, który nazywa się Gherkin, praktycznie brzmiących jak normalne (nieco sformalizowane) zdania. Każda linijka takiego testu, jest nazywana krokiem. Dla kroków pisane są ich definicje, czyli wyrażenia regularne, w których zawarta jest treść testu. W trakcie uruchomienia testu, kroki są analizowane pod względem zgodności z definicjami i jeśli do którejś pasują, następuje wywołanie zawartego w definicji kroku testu. Capybara
umożliwia testowanie aplikacji opartych o Rack i dostarcza metody do wysyłania zapytań do serwerów rackowych, oraz analizowaniu odpowiedzi. Czyli na przykład sprawdzaniu, czy na stronie znajduje się jakiś tekst, lub wypełnianiu i wysyłaniu formularzy. W końcu Rspec
to podstawowa biblioteka do BDD w Rubym, dostarczająca szereg przydatnych metod, zastępujących Test::Unit.
Hello World w Sinatrze
W pierwszym kroku stworzymy zaczyn aplikacji, potem dopiero napiszemy do niej test. Utwórzmy plik pong.rb
z następującą zawartością:
require 'rubygems' require 'sinatra' get '/' do 'Hello ping-pong!' end
Te pięć linijek, to najprostsze Hello World w Sinatrze. Sprawdźmy zatem, czy działa, uruchamiając serwer z konsoli:
ruby pong.rb
W tym momencie, na localhoście na porcie 4567 powinniśmy ujrzeć Hello ping-pong.
Teraz pora na ciekawszą część.
Konfiguracja środowiska testowego
mkdir features
W tym katalogu trzymane są wszystkie scenariusze uruchamiane poleceniem cucumber
. W nim powinien się znaleźć katalog support
. W nim trzymamy wszystkie pliki, które są potrzebne przy starcie cucumber’a, a nie są definicjami kroków. Jednym z nich jest features/support/env.rb
i to w nim umieszcza się konfigurację środowiska. Po pierwsze musimy wczytać utworzony wcześniej plik startowy aplikacji.
require File.join(File.dirname(__FILE__), '..', '..', 'pong')
Będziemy również potrzebowali następujących bibliotek:
require 'capybara' require 'capybara/cucumber' require 'spec'
Cucumber uruchamia scenariusze w obiekcie, który nazywa się World
. Wszystkie metody zdefiniowane wewnątrz tego obiektu są dostępne w definicjach kroków. Zależy nam na dwóch rzeczach: chcemy uruchamiać scenariusze z użyciem capybary
, oraz móc korzystać z method rspeca
. Musimy więc dodać poniższy wpis w pliku features/support/env.rb
:
World do Capybara.app = Sinatra::Application include Capybara include Spec::Expectations include Spec::Matchers end
Tworzymy pierwszy scenariusz
Mając tak skonfigurowane środowisko, stwórzmy pierwszy scenariusz: features/home_page.feature
.
Feature: Home page In order to join ping-pong league As a guest I want to see home page of ping pong app Scenario: Accessing home page Given I am the guest When I go to the home page Then I should see "Hello ping-pong"
Na początku pliku znajdują się nasze założenia i opis, wyjaśniający, dlaczego dana funkcjonalność jest nam potrzebna. Właściwy scenariusz (czyli tekst, który wykonywany jest jako test), zaczyna się dopiero po w linijce 6, słowem kluczowym Scenario
.
Gdy wywołamy polecenie cucumber
, to zobaczymy, że nasz scenariusz nie przeszedł i dostaniemy informację, że należy zaimplementować następujące kroki:
Given /^I am the guest$/ do pending # express the regexp above with the code you wish you had end When /^I go to the home page$/ do pending # express the regexp above with the code you wish you had end Then /^I should see "([^\"]*)"$/ do |arg1| pending # express the regexp above with the code you wish you had end
Stwórzmy zatem katalog features/step_definitions
. Wszystkie pliki rb, które się tam znajdą, zostaną domyślnie użyte przez cucumbera, do sparsowania kroków. Nasz plik może się nazywać sinatra_steps.rb
. Wypełnijmy go.
Given
, when
, then
oraz and
, to słowa od których musi zaczynać się każdy krok. Praktycznie nie ma znaczenia, którego użyjemy, ale zdecydowanie zalecane jest, by używać tego słowa, które najbardziej odpowiada sytuacji.
Pierwszy krok, jest pusty, nie musimy nic robić, żeby zostać gościem.
Given /^I am the guest$/ do end
Aby wywołać jakąś stronę, skorzystamy z funkcji visit
, której podajemy ścieżkę do odwiedzenia.
When /^I go to the home page$/ do visit '/' end
Napiszmy prosty warunek sprawdzający, że na stronie znajduje się poszukiwany tekst.
Then /^(?:|I )should see "([^\"]*)"$/ do |text| page.should have_content(text) end
Ponownie wywołajmy cucumber
, by naszym oczom ukazał się zielony widok.
1 scenario (1 passed) 3 steps (3 passed)
Bingo! Znaczy to, że scenariusz przeszedł pomyślnie i wszystkie trzy kroki są spełnione. Właśnie napisaliśmy i przetestowaliśmy najprostszą aplikację w Sinatrze.
W następnym odcinku
Mając wszystko ładnie przygotowane, będziemy mogli się zająć dodaniem obsługi bazy danych i umożliwić użytkownikom rejestrację i logowanie, ale o tym w następnym odcinku.
Przykład dostępny jest oczywiście na githubie: http://github.com/tjeden/sinatra-pong/tree/0.1
Część 2:
http://rubysfera.pl/2010/5/uwierzytelnianie-w-sinatrze-z-data-mapperem