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.
If you use TDD, starting with BDD will be easy – it’s basically a set of best practices for it. BDD has a set of simple rules, which tell how to write specs and what to test. Specifications are divided into three parts: Given (setting up test conditions), When (invoking action on subject) and Then (assertions). Tests should have descriptive names and existing test frameworks allow for using methods and assertions that are similar to natural language – all of which combined gives us tests that are readable by both technical and non-technical users. Good naming conventions prove useful during regression tests.
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 z doskonałym zestawem 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.