Współcześni programiści wykorzystują coraz więcej zwinnych praktyk w swojej codziennej pracy. Nawet projekty zgodne ze standardowym cyklem życia oprogramowania mogą skorzystać na ich adaptacji. Automatyczne testowanie i TDD wniosły więcej pewności do naszej pracy, ułatwiły wdrażanie modyfikacji do istniejących funkcji i często prowadziły nas do lepszego projektowania kodu. Ale teraz to nie wystarczy. Musimy zwiększyć korzyści płynące z testów do granic możliwości, a BDD na to pozwala. BDD opiera się na TDD i dodaje do jego praktyk wiele wartości. Wprowadza wszechobecny język do projektu, pozwala na lepszą komunikację między klientem a programistami. Oferuje wiele kierownikom projektów i liderom, ale także znacznie ułatwia życie programistom. Przestrzeganie zasad BDD daje nam jasne wymagania, testy są łatwiejsze do zrozumienia i mogą służyć jako dokumentacja. BDD przenosi punkt ciężkości na testowanie i daje nam pewność, że testujemy to, co powinniśmy testować - zachowanie.
Jeśli używasz TDD, rozpoczęcie pracy z BDD będzie łatwe - jest to w zasadzie zestaw najlepszych praktyk. BDD ma zestaw prostych zasad, które mówią, jak pisać specyfikacje i co testować. Specyfikacje są podzielone na trzy części: Given (ustalenie warunków testu), When (wywołanie akcji na obiekcie) i Then (asercje). Testy powinny mieć opisowe nazwy, a istniejące frameworki testowe pozwalają na używanie metod i asercji, które są podobne do języka naturalnego - wszystko to razem daje nam testy, które są czytelne zarówno dla użytkowników technicznych, jak i nietechnicznych. Dobre konwencje nazewnictwa okazują się przydatne podczas testów regresji.
BDD zawiera również zestaw wytycznych dla obiektów testowych. W przeciwieństwie do TDD przenosi nacisk z testowania implementacji na testowanie zachowania - a korzystanie z tego prowadzi do lepszego projektowania i zapewnia większą elastyczność w przypadku konieczności wprowadzenia zmian. Specyfikacje powinny być jak pisemne i wykonywalne wymagania klienta - te wysokiego poziomu powinny działać jak testy akceptacyjne. Celem jest napisanie testów w sposób, który wymaga ich zmiany tylko wtedy, gdy zmieniają się wymagania. Korzystanie z BDD daje nam pewność, że testujemy to, co naprawdę musi być pokryte i jest bardziej pragmatycznym podejściem niż TDD.
Jeśli chcesz zobaczyć BDD w akcji, polecamy Ruby. Jest to potężny i przyjemny w użyciu język, który ma doskonały zestaw narzędzi BDD.
Ogórek
Cucumber jest najpopularniejszym frameworkiem do BDD w Ruby. Wprowadza on specjalny język, zwany Gherkin, w którym będziesz pisał swoje testy. W przeciwieństwie do RSpec, funkcje opisane w Gherkin są zwykłym tekstem, a nie kodi jako taki może - i powinien - być zrozumiały dla każdego, w szczególności dla klienta.
Funkcja Cucumber wygląda następująco (przykład zaczerpnięty z wiki Cucumber):
Funkcja: Krótki, ale opisowy tekst tego, co jest pożądane.
Tekstowy opis wartości biznesowej tej funkcji
Reguły biznesowe, które regulują zakres funkcji
Wszelkie dodatkowe informacje, które ułatwią zrozumienie funkcji
Scenariusz: Pewna możliwa do określenia sytuacja biznesowa
Biorąc pod uwagę pewien warunek wstępny
I jakiś inny warunek wstępny
Gdy jakieś działanie zostanie podjęte przez aktora
I jakieś inne działanie
I jeszcze inne działanie
Wtedy zostanie osiągnięty jakiś testowalny wynik
I dzieje się też coś innego, co możemy sprawdzić
Scenariusz: Inna sytuacja
...
Funkcje te zostaną szczegółowo opisane później.
Korzystanie z Cucumber w Ruby on Rails
Instalacja
Pierwszy krok do wykorzystania ogórka w projekt instaluje go. Wystarczy dodać te dwa klejnoty do pliku Gemfile:
group :test do
gem 'cucumber-rails', :require => false
gem 'database_cleaner'
end
Połącz je, uruchamiając instalacja pakietui wygenerować skrypty i katalogi Cucumber za pomocą następującego polecenia:
rails generate cucumber:install
Spowoduje to utworzenie config/cucumber.yml, skrypt/ogórek i funkcje/katalogktóry będzie zawierał .feature a także definicje kroków i pliki pomocnicze. Aby uruchomić funkcje, należy użyć nowego polecenia rake:
ogórek grabiony
Cechy
Przyjrzyjmy się bliżej funkcjom. Funkcja to coś, co aplikacja ma lub robi - na przykład okresowo wysyła biuletyn lub pozwala użytkownikowi publicznie udostępniać swoje zdjęcia. Jedna funkcja składa się z wielu scenariuszy, które opisują, jak ta funkcja działa w różnych kontekstach.
Aby zademonstrować podstawowe użycie Cucumbera w Railsach, napiszemy funkcję od podstaw. Ta przykładowa funkcja będzie pierwszą, którą napiszemy w aplikacji, która zostanie pokazana w nadchodzącej drugiej części tego artykułu. Ta aplikacja pozwoli użytkownikowi tworzyć przedmioty i sklepy (sklepy sprzedają przedmioty), a następnie tworzyć listy zakupów.
W najprostszej wersji, po skompilowaniu listy zakupów, aplikacja pokaże, w których sklepach produkty, które użytkownik chce kupić, są najtańsze.
Najpierw utwórz nowy plik o nazwie create_item.feature w cechy/ katalog. Na górze katalogu .feature znajduje się plik Cecha słowo kluczowe, po którym następuje jego krótki opis. Na przykład:
Funkcja: Tworzenie przedmiotów
W kolejnych linijkach możesz napisać cel biznesowy, który zaimplementuje tę funkcję. Ponieważ Cucumber ignoruje tekst napisany przed pierwszym Scenario, nie jest konieczne pisanie czegokolwiek, ale jest to zdecydowanie dobry pomysł.
W celu łatwego tworzenia list zakupów z artykułami sprzedawanymi w pobliskich sklepach
Jako użytkownik
Chcę dodać produkty do systemu
W powyższym fragmencie widać dość popularny wzorzec, za pomocą którego można opisać cele biznesowe. Składa się on z trzech części: dlaczego funkcja jest potrzebna, kto jej chce i co to jest. Oczywiście nie musisz podążać za tym formatem, ale pamiętaj, aby zawrzeć odpowiedzi na te trzy pytania w swoim opisie.
Scenariusze
Następnie piszemy kilka scenariuszy. Każdy scenariusz zaczyna się od słowa kluczowego "Scenario" i zawiera wiele kroków.
Scenariusz: tworzenie unikalnego elementu
Biorąc pod uwagę, że istnieje pozycja "Mleko"
Kiedy przechodzę do strony głównej
I tworzę pozycję "Chleb"
Następnie widzę "Chleb" na liście przedmiotów
Tak więc, jeśli ktoś utworzył przedmiot o nazwie Mleko, to utworzenie Chleba jest możliwe i skutkuje pojawieniem się Chleba na liście przedmiotów. Nie powinniśmy testować tworzenia rekordu w bazie danych, ponieważ fakt ten nie ma żadnej realnej wartości dla klienta.
Kroki scenariusza wykorzystują trzy główne słowa kluczowe:
Biorąc pod uwagęza dostarczenie kontekstu do scenariusza
Kiedydo opisywania działań
Następniedo opisywania wyników
Ważne jest, aby pamiętać, że Cucumber ignoruje słowo kluczowe kroku, od którego się zaczyna i dopasowuje tylko późniejszą część. W związku z tym kroki można rozpoczynać od "And" w dowolnym miejscu, w którym wydaje się to naturalne. Jedyną zasadą wyboru właściwego słowa kluczowego jest to, że scenariusz musi być łatwo zrozumiały.
Definicje kroków
Uruchomienie Cucumber daje teraz następujące wyniki:
[...]
Funkcja: Tworzenie przedmiotów
W celu łatwego tworzenia list zakupów z przedmiotami sprzedawanymi w pobliskich sklepach
Jako użytkownik
Chcę dodać przedmioty do systemu
Scenariusz: tworzenie unikalnego przedmiotu # features/create_item.feature:6
Biorąc pod uwagę, że istnieje pozycja "Mleko" # features/create_item.feature:7
Niezdefiniowany krok: "there is a "Milk" Item" (Cucumber::Undefined)
[...]
Dzieje się tak, ponieważ Cucumber nie wie, co mamy na myśli, gdy mówimy "istnieje Milk Item". Aby dodać jakieś znaczenie do kroków, należy zdefiniować je w sekcji step_definitions katalog.
Zalecanym sposobem organizowania definicji kroków jest podzielenie ich według domeny. Na przykład, większość utworzonych przez nas kroków należy do domeny Item. Dlatego powinniśmy utworzyć plik o nazwie step_definitions/item_steps.rb i umieść tam następujący kod:
Given "there is a "$name" Item" do |name|
Fabricate :item, name: name
end
When "I create "$name" Item" do |name|
wewnątrz "#new_item" do
fill_in "Nazwa", z: nazwa
click_on "Create"
end
end
Then "I see "$name" on the Item list" do |name|
within ".items" do
expect(page).to have_content name
end
end
Definicje kroków będą zazwyczaj oparte na Capybara. Jeśli nie jesteś zaznajomiony z Capybara, koniecznie sprawdź linki na końcu tego artykułu.
Jest jeszcze jeden krok, który wymaga zdefiniowania i tak naprawdę nie pasuje do kroków Item. Można go umieścić w main_page_steps.rb:
Kiedy "przechodzę do strony głównej" wykonaj
visit root_path
koniec
Wnioski
Jest to bardzo prosta historia dla bardzo prostej funkcji. Jej celem było zademonstrowanie podstawowych koncepcji BDD, tak jak są one używane w Cucumber. Pisanie dobrych historii wymaga jednak nieco więcej. Jako programista będziesz musiał całkowicie zmienić swój sposób myślenia - zapomnieć o implementacji i zamiast tego skupić się na celach biznesowych. Cucumber ułatwia to przejście dzięki sprytnemu wykorzystaniu historyjek tekstowych.