Dieses Tutorial zeigt, wie sich Akzeptanztests für Web-Anwendungen mit Cucumber, Capybara, Poltergeist und PhantomJS schreiben lassen. Unterwegs werden wir auch einige andere interessante Technologien wie Node.js and AngularJS streifen. Dies ist der zweite Teil einer Mini-Serie zu Cucumber – wem Cucumber bisher noch nicht bekannt ist, kann auch mit dem ersten Teil einsteigen, der das Setup und die Grundlagen von Cucumber behandelt.
Der Tool-Stack im Detail – Capybara, Poltergeist und PhantomJS
Bevor wir unseren ersten Test schreiben, sollten wir uns einen Moment Zeit nehmen, um die Werkzeuge zu betrachten, die wir zusätzlich zu Cucumber noch einsetzen werden:
- Capybara nennt sich selbst ein „Akzeptanztest-Framework für Web-Anwendungen“. Moment mal – ist Cucumber nicht schon ein Akzeptanztest-Framework? Warum benötigen wir noch ein weiteres in unserem Stack? Zuerst einmal ist Cucumber ein Framework für Behaviour Driven Development und nicht per se ein Akzeptanztest-Framework. Man könnte Cucumber für Unit Tests einsetzen, für Akzeptanztests oder für irgendetwas dazwischen. Des Weiteren hat Cucumber nichts mit Web-Anwendungen am Hut. Cucumber gibt uns nur die Möglichkeit, unsere Tests (oder Specs oder Szenarios, wie immer man sie auch nennen möchte) in einer sehr lesbaren, nicht-technischen Form (Gherkin) zu schreiben und auszuführen. Capybara hingegen kümmert sich nun um den Aspekt „Web-Anwendung“ und versteckt die Details, die notwendig sind, um einen Browser fernzusteuern (via Selenium oder Poltergeist) hinter einer schicken API. Des Weiteren lässt sich Capybara gut mit Cucumber kombinieren (siehe Abschnitt Using Capybara with Cucumber in der Capybara-Dokumentation). Es ist genau der richtige Abstraktionslevel, um Tests für Web-Anwendungen zu schreiben. Natürlich könnte man auch in den Cucumber Step Definitions so etwas wie Selenium direkt verwenden, aber meiner Meinung nach ist das zu low-level und erfordert deutlich mehr Code für das gleiche Ergebnis.
- Poltergeist ist ein PhantomJS Treiber für Capybara. Es stellt die Verbindung zwischen Capybara und PhantomJS dar. Nachdem Poltergeist einmal als Treiber in Capybara konfiguriert ist, interagiert man nicht mehr direkt mit Poltergeist oder PhantomJS, sondern nur noch mit der Capybara API.
- PhantomJS ist ein vollständiger Browser, der allerdings headless (also ohne graphische Anzeige) läuft. Es basiert auf WebKit und unterstützt alle wichtigen Web-Standards (CSS, JavaScript, …). Es eignet sich ideal für automatisierte Tests von Web-Anwendungen, da es ausgesprochen einfach ist, es auf einem CI-Server laufen zu lassen (selbst, wenn auf diesem kein X installiert ist).
Setup
Einrichten der zu testenden Anwendung
Da dieses Tutorial sich mit dem Testen von Web-Anwendungen beschäftigt, benötigen wir offensichtlich eine solche. Wer öfter Beiträge im codecentric-Blog liest, dem ist vielleicht schon einmal die „Movie Database“ in einer Ihrer verschiedenen Inkarnationen begegnet. Da ich mich kaum für Filme interessiere, dafür aber umso mehr für Hörbücher, wird unsere Beispielanwendung diesmal der „Audiobook Collection Manager“ sein, eine sehr einfache, auf AngularJS basierende CRUD-Anwendung, mit der man seine Hörbuch-Sammlung verwalten kann. Unter https://github.com/basti1302/audiobook-collection-manager-ui findet sich eine kurze Anleitung, um die Anwendung einzurichten. Im Verlauf der Installation muss auch Storra per git geklont werden, ein simpler, in Node.js geschriebender REST-Service, der vom Audiobook Collection Manager Frontend zur Speicherung der Daten benutzt wird. Kleiner Hinweis am Rande: Im ersten Teil des Tutorials hatte ich erwähnt, dass Cucumber mittlerweile auf viele andere Sprachen (außer Ruby) portiert wurde. Wer einen Blick auf cucumber.js , den JavaScript-Port von Cucumber, werfen möchte, sollte einmal in das Verzeichnis storra/features
schauen.
Wenn der Audiobook Collection Manager eingerichtet ist und läuft, kann man kurz manuell ein wenig in der Anwendung umherklicken, um zu sehen, was man damit machen kann (nicht viel – es ist ja auch nur eine Beispielanwendung).
Capybara und Poltergeist einrichten
Wer den ersten Teil des Tutorials verfolgt hat, sollte das Beispiel-Projekt bereits ausgecheckt haben. In diesem Fall muss
1git checkout 03_setup_capybara
ausgeführt werden, um den neuen Gemfile mit den Gems für Capybara und Poltergeist zu bekommen. (In diesem Branch wurde das Cucumber Feature und die dazugehörige Step-Datei aus dem ersten Teil des Tutorials entfernt, da wir es nicht mehr benötigen.)
Wenn das Repository noch nicht ausgecheckt ist, sollte das jetzt nachgeholt werden.
1git clone -b 03_setup_capybara https://github.com/basti1302/audiobook-collection-manager-acceptance.git
Da sich das Gemfile geändert hat, muss nun als erstes bundle install
ausgeführt werden. Damit werden die Capybara- und Poltergeist-Gems und deren Abhängigkeiten installiert.
Im ersten Teil des Tutorials wurde auch PhantomJS installiert. Wer diesen Schritt ausgelassen hat, kann das jetzt nachholen – http://phantomjs.org/download.html.
Der Branch von audiobook-collection-manager-acceptance
, den wir gerade ausgecheckt haben, beinhaltet bereits den erforderlichen Code zu Konfiguration von Capybara und Poltergeist. An dieser Stelle ist also nichts mehr zu tun. Wir können uns den Konfigurations-Code kurz anschauen, er ist aufgeteilt auf features/support/env.rb
und features/support/hooks.rb
. Die Datei env.rb
beginnt mit einigen require
-Anweisungen:
1require 'rspec/expectations' 2require 'capybara/cucumber' 3require 'capybara/poltergeist'
Die Anweisung require 'rspec/expectations'
habe wir bereits im ersten Teil des Tutorials diskutiert – sie sorgt dafür, dass die RSpec Object Expectations in allen Step-Files verfügbar sind. require 'capybara/cucumber'
bewirkt das gleiche für die Methoden der Capybara API. require 'capybara/poltergeist'
ist erforderlich, um Poltergeist als Browser-Treiber für Capybara zu registrieren.
Nach dem require
-Block kommt ein etwas längliches if-else-Konstrukt:
1if ENV['IN_BROWSER']
2 # On demand: non-headless tests via Selenium/WebDriver
3 # To run the scenarios in browser (default: Firefox), use the following command line:
4 # IN_BROWSER=true bundle exec cucumber
5 # or (to have a pause of 1 second between each step):
6 # IN_BROWSER=true PAUSE=1 bundle exec cucumber
7 Capybara.default_driver = :selenium
8 AfterStep do
9 sleep (ENV['PAUSE'] || 0).to_i
10 end
11else
12 # DEFAULT: headless tests with poltergeist/PhantomJS
13 Capybara.register_driver :poltergeist do |app|
14 Capybara::Poltergeist::Driver.new(
15 app,
16 window_size: [1280, 1024]#,
17 #debug: true
18 )
19 end
20 Capybara.default_driver = :poltergeist
21 Capybara.javascript_driver = :poltergeist
22end
Es nicht notwendig, das im Detail zu analysieren, der springende Punkt ist: Im Standardfall benutzen wir den else
-Zweig. Dort wird Poltergeist als Treiber für Capybara registriert, Poltergeist wiederum benutzt dann PhantomJS. Da PhantomJS headless läuft, ist es sehr einfach in eine Continuous-Integration-Umgebung zu integrieren.
Wenn man sich das Ganze allerdings ab und an in einem richtigen Browser anschauen will, kann man die Tests folgendermaßen starten:
1IN_BROWSER=true bundle exec cucumber
oder unter Windows:
1SET IN_BROWSER=true 2bundle exec cucumber
Wenn diese Umgebungsvariable vorhanden ist, wird Selenium WebDriver statt Poltergeist und Firefox statt PhantomJS benutzt, so dass man sich die Szenarien live und in Farbe anschauen kann. Wem das zu schnell geht, kann sie mit
1IN_BROWSER=true PAUSE=1 bundle exec cucumber
oder unter Windows
1SET IN_BROWSER=true 2SET PAUSE=1 3bundle exec cucumber
starten, so dass Cucumber nach jedem Step eine Sekunde wartet.
Der Rest von env.rb
definiert einige Konstanten sowie Hilfsmethoden, um auf die getestete Anwendung zuzugreifen.
hooks.rb
enhält momentan nur Folgendes:
1After do |scenario|
2 if scenario.failed?
3 save_page
4 end
5end
Dies registriert einen sogenannten Hook, der nach jedem Szenario aufgerufen wird. Wenn das Szenario fehlgeschlagen ist, schreibt Capybara eine Momentaufnahme des HTMLs der aktuellen Seite in eine Datei. Cucumber documentation enthält weitergehende Informationen zu Hooks.
Testen der Web-Anwendung
Das erste Feature mit Capybara
Nachdem nun das Setup und die Konfiguration erledigt ist, können wir mit unserem ersten Szenario loslegen.
Die erste Funktion, die wir testen werden, ist das Auflisten aller Hörbücher in der Sammlung. Ohne weitere Umschweife schreiben wir einfach auf, welches Verhalten wir von der Anwendung erwarten, wenn der Benutzer auf die Seite geht, die die Liste aller Einträge darstellt. Die Datei features/list_audiobooks.feature
könnte folgendermaßen aussehen:
1Feature: Display the list of audio books 2 In order to know which audio books the collection contains 3 As an audio book enthusiast 4 I want to see a list of all audio books 5 6 Scenario: Display the list of all audio books in the collection 7 Given some audio books in the collection 8 When I visit the list of audio books 9 Then I see all audio books
Anmerkung: Sämtlicher Code der in diesem Abschnitt zu sehen ist (das Cucumber-Feature, der Step-File und die Datei storage.rb) ist im Branch
04_list_audiobooks
verfügbar. Mitgit checkout 04_list_audiobooks
kann man sich den Code holen.
Zur Erinnerung: In einem Szenario kann man im Wesentlichen schreiben, was man möchte, solange jede Zeile mit Given, When, Then oder And beginnt. Man muss (und sollte) an dieser Stelle noch nicht darüber nachdenken, wie man die einzelnen Schritte später implementiert. Stattdessen kann man sich ganz darauf konzentrieren, wie man die aktuellen Anforderung formuliert. Aus diesem Grund ist es oft günstiger, das Szenario zuerst zu schreiben und die Step Definitions erst im Anschluss. Das obige Szenario sollte weitestgehend selbsterklärend sein.
Wir können bei Bedarf nun wieder bundle exec cucmber
ausführen, um von Cucumber Vorschläge für die Step Definitions zu bekommen. Die Step Definitions kommen diesmal in die Datei features/step_definitions/audiobooks.rb
:
1#encoding: utf-8 2 3Given /^some audio books in the collection$/ do 4 upload_fixtures backend_url('audiobooks'), $fixtures 5end 6 7When /^I visit the list of audio books$/ do 8 visit ui_url '/index.html' 9end 10 11Then /^I see all audio books$/ do 12 page.should have_content 'Coraline' 13 page.should have_content 'Man In The Dark' 14 page.should have_content 'Siddhartha' 15end
Diese Step Definitions benutzen die Capybara DSL, um die Schritte des Szenarios zu implementieren – mehr Informationen zur Capybara DSL findet man auf der Capybara Github-Seite oder auf rubydoc.info .
Der „Given“ Step ruft upload_fixtures
auf, eine Methode die in features/support/storage.rb
implementiert ist und Storra (der Persistenz-Service der von der AngularJS UI benutzt wird) direkt anspricht, um einige Hörbücher in die Datenbank zu schreiben. Der Code hat nicht mit Cucumber oder Capybara zu tun, daher gehe ich an dieser Stelle nicht weiter darauf ein.
Der „When“ Step: Klammern sind in Ruby bei Methodenaufrufen optional, daher ist visit ui_url '/index.html'
äquivalent zu visit(ui_url('/index.html'))
(meiner Meinung ist die Version ohne Klammern flüssiger lesbar, aber das ist natürlich Geschmackssache). ui_url
ist eine Hilfsmethode aus env.rb
die einen Pfad in eine vollständige URL in der zu testenden Anwendung übersetzt. visit
schließlich ist eine Methode von Capybara, die zu der gegebenen URL navigiert. Insgesamt veranlasst visit ui_url '/index.html'
also den Browser (PhantomJS in diesem Fall) http://localhost:8000/app/index.html
abzurufen, die Seite, die die Hörbücher auflistet.
Der „Then“ Step benutzt Capybaras page
-Objekt (welches die aktuelle Seite repräsentiert, also den DOM, der momentan im Browser vorliegt) um zu verifizieren, dass drei bestimmte Textfragmente vorhanden sind. Nehmen wir einmal an, dass der Step Given some audio books in the collection
drei Hörbücher hinzufügt, und zwar „Coraline“ von Neil Gaiman, „Man in the Dark“ von Paul Auster und „Siddhartha“ von Herman Hesse. Wenn man sich die Dokumentation von Capybara ansieht, würde man nun erwarten, dass die Überprüfung in etwa so erfolgt: page.has_content?('Coraline')
. Um das ganze etwas interessanter zu machen, benutzen wir hier die Fähigkeit von RSpec, zu jedem Prädikat (eine Methode, deren Name mit „?“ endet) bei Bedarf zur Laufzeit einen Custom Matcher zu generieren. Siehe dazu auch die RSpec Matcher Doku. Die RSpec-Bibliothek nutzt hierzu Meta-Programming in Ruby und daher können wir page.should(have_content('Coraline'))
schreiben oder eben ohne Klammern page.should have_content 'Coraline'
.
Ein Wort zu Test-Daten
Wenn man das Feature mehrfach ausführt und dann http://localhost:8000/app/index.html im Browser öffnet, wird man feststellen, dass die Liste ziemlich gewachsen ist, sie enthält jetzt jeweils mehrere Exemplare der Hörbücher, die im „Given“ Step hinzugefügt wurden. Das kann zu einem echten Problem werden, insbesondere, wenn wir später Funktionen wir das Hinzufügen oder Löschen von Hörbüchern testen wollen. Die Tests sind nicht mehr voneinander isoliert, da sie auf derselben Datenbank operieren. Beispiel: Ein Szenario für das Hinzufügen eines neuen Hörbuchs, dass beispielsweise den Titel „Foobar“ in die Sammlung einfügt. Um zu testen, ob das Hinzufügen erfolgreich war, würden wir vermutlich page.should have_content 'Foobar'
in einem „Then“ Step ausführen, nachdem wir zur Liste aller Hörbücher zurücknavigiert haben. Nun nehmen wir an, dass der Test einige Male erfolgreich durchläuft. Aber was, wenn später die Funktion zum Hinzufügen im produktiven Code kaputt geht? Unser Cucumber-Szenario wäre unter Umständen immer noch grün, da bereits mehrere Exemplare von „Foobar“ in der Datenbank sind und damit in der Liste auftauchen. Das ist der Worst Case für einen automatisierten Test: Der Test ist grün obwohl der produktive Code kaputt ist. Also müssen wir uns darum kümmen.
Dieses Problem kann bei jeder Anwendung bei Akzeptanztests auftreten und es gibt mindestens zwei Lösungen dafür:
- Vor oder nach jedem Test wird die komplette Datenbank gelöscht. Das ist oft die einfachere Option. Diese Strategie macht es natürlich erforderlich, im CI einen gesondertes Umgebung für die Akzeptanztests bereitzustellen – zusätzlich zu einer Stage für manuelle Tests. Dies sollte allerdings jedes nicht triviale Projekt ohnehin haben.
- Die Tests werden dadurch isoliert, dass jeder Test einen separaten „Namensraum“ benutzt. Hier hängt es vom Domänenmodell ab, ob diese Strategie genutzt werden kann. Kurzes Beispiel: Angenommen, wir haben ein Kunden Objekt, dem ein oder mehrere Bestellungen zugeordnet sind, denen wiederum Artikel zugeordnet sind. Ein Kunde interagiert immer nur mit seinen eigenen Bestellungen und sieht auch nur diese. In einem solchen Fall könnte jeder Test im ersten Schritt einen neuen Kunden anlegen (mit einer neuen, eindeutigen ID) um so die Tests voneinander zu isolieren.
Wir verwenden die erste Strategie und löschen vor jedem Test per Storra die gesamte Hörbuch-Sammlung. Dazu wird Folgendes zu features/support/hooks.rb
hinzugefügt:
1Before do 2 delete_database backend_url('audiobooks') 3end
Und die Methode delete_database
wird in features/support/storage.rb
implementiert:
1def delete_database(url)
2 RestClient.delete url
3end
Hinweis:
backend_url
ist infeatures/support/env.rb
definiert und gibt die URL zurück, unter der die Collection'audiobooks'
von Storra verwaltet wird.
Weitere Tests für die Liste der Hörbücher
Hinweis: Der Code des folgenden Szenarios ist per
git checkout 05_filter
verfügbar. Dieser Branch enthält auch den im vorigen Abschnitt besprochenen Hook zum Löschen der Datenbank.
Wenn man sich im Audio Book Collection Manager etwas umschaut, fällt einem evtl. das Texteingabefeld mit dem Label „Filter“ auf. Wenn man anfängt, in diesem Feld etwas zu tippen, werden nur noch Hörbücher angezeigt, die zu dem Suchbegriff passen. Tippt man also z. B. „Cor“, wird das Hörbuch „Coraline“ angezeigt, alle anderen Titel nicht.
Um dies in einem Cucumber-Szenario auszudrücken, können wir den folgenden Code zu features/list_audiobooks.feature
hinzufügen:
1Scenario: Filter the list 2 Given some audiobooks in the collection 3 When I visit the list of audiobooks 4 And I search for "Cor" 5 Then I only see titles matching the search term 6 When I remove the filter 7 Then I see all audiobooks again
Um die Steps zu implementieren, fügen wir Folgendes zu features/step_definitions/audiobooks.rb
hinzu:
1When /^I search for "(.*?)"$/ do |search_term|
2 fill_in('filter', :with => search_term)
3 @matching_titles = ['Coraline']
4 @not_matching_titles = ['Man In The Dark', 'Siddharta']
5end
6
7When /^I remove the filter$/ do
8 # funny, '' (empty string) does not work?
9 fill_in('filter', :with => ' ')
10 @matching_titles = @not_matching_titles = nil
11end
12
13Then /^I see all audiobooks(?: again)?$/ do
14 page.should have_content 'Coraline'
15 page.should have_content 'Man In The Dark'
16 page.should have_content 'Siddhartha'
17end
18
19Then /^I only see titles matching the search term$/ do
20 @matching_titles.each do |title|
21 page.should have_content title
22 end
23
24 @not_matching_titles.each do |title|
25 page.should have_no_content title
26 end
27end
Betrachten wir die Step Definitions eine nach der anderen.
When I search for...
: Die erste Zeile (fill_in('filter', :with => search_term)
) benutzt Capybaras API um einen Wert in das Texteingabefeld einzutragen. Der Wert wird durch die Capturing Group des reguläre Ausdrucks festgelegt. Wird der Step also mitWhen I search for "Foobar"
aufgerufen, würde „Foobar“ in das Eingabefeld eingetragen. Die nächsten beiden Zeilen setzen die Instanzvariablen@matching_titles
und@not_matching_titles
. Hier werden also Erwartungen (oder besser: erwartete Werte) in einem When-Step definiert, damit diese später in einem Then-Step überprüft werden können. In diesem Fall werden die erwarteten Werte direkt im nächsten Schritt geprüft. Diese Vorgehensweise mag diskussionswürdig sein, da Erwartungen in einem When-Step eigentlich nichts zu suchen haben, dafür ist ja der Then-Step da. Allerdings erlaubt diese Technik oft auf pragmatische Art und Weise, einen Then-Step mit verschiedenen Erwartungen (die dann in verschiedenen When-Steps definiert werden) zu benutzen. In diesem speziellen Fall gibt es allerdings auf jeden Fall noch Verbesserungspotenzial, da nur der Text fürfill_in
variabel ist (die Variablesearch_term
, aus der Capturing Group), die Werte für@matching_titles
und@not_matching_titles
jedoch fest sind.Then I only see titles matching the search term
: Dieser Schritt benutzt die erwarteten Werte, die im When-Step festgelegt wurden. Wir überprüfen, dass alle Hörbuch-Titel, die zum Filter passen, angezeigt werden. Ebenso überprüfen wir für die Titel, die nicht zum Filter passen, dass sie auch tatsächlich nicht angezeigt werden.When I remove the filter
: Dieser Schritt entfernt den eingegebenen Text wieder aus dem Filter-Feld.- Die Step-Definition
Then /^I see all audiobooks(?: again)?$/ do
ist unsere bereits existierende Step-Definition (Then /^I see all audiobooks/ do
), nur dass der reguläre Ausdruck mit einer optionalen Non-Capturing Group(?: again)?
erweitert wurde, damit sich das Szenario flüssiger liest. (Wenn der obige Code per Copy and Paste in die vorhandeneaudiobooks.rb
eingefügt wurde, muss die alte Step-Definition ohne erweiterten regulären Ausdruck gelöscht werden, um mehrdeutige Steps zu vermeiden.)
AJAX-Funktionalität mit Capybara testen
Lehnen wir uns einen Moment zurück – was genau passiert in dem Test, den wir gerade implementiert haben? Die getestete Anwendung ist mit AngularJS implementiert, also eine Single Page Application . Es findet keine Navigation statt, die Seite wird nie neu geladen. Alles passiert auf einer Seite durch asynchrones JavaScript, DOM-Manipulation und asynchronen Datenaustausch mit dem Backend (Storra). Die Filter-Funktionalität, die wir im letzten Abschnitt getestet haben passiert zum Beispiel komplett client-seitig. Wenn sich der Filter ändert, werden einige Einträge aus dem DOM entfernt, andere werden ggf. wieder angezeigt.
Hat uns das das Testen erschwert? Waren die Steps dadurch komplizierter zu implementieren? Haben wir speziellen Code benötigt, um auf die asynchronen Teile zu warten? Nein! Wir haben uns bis jetzt eigentlich noch gar keinen Gedanken darum gemacht. Der Grund dafür ist folgender: Capybara nimmt einfach grundsätzlich an, dass in einer modernen Web-Anwendung potenziell alles asynchron sein kann. Immer, wenn man per Capybara überprüft, ob bestimmte Inhalte da sind oder eine gewisse Bedingung erfüllt ist, wartet Capybara darauf, dass der Inhalt erscheint oder die Bedingung erfüllt ist, anstatt es nur einmalig zu überprüfen.
Das ist genau das Verhalten, dass ich von einer guten Browser-Abstraktionsschicht heute erwarte: Wenn ich Akzeptanztests schreibe, will ich nicht darüber nachdenken müssen, ob die Anwendung den erwarteten Inhalt durch Navigation zu einer anderen Seite oder durch ein partielles DOM-Update erzeugt. Ich will nur testen, ob der Inhalt da ist. Des Weiteren will ich meinen Test nicht anpassen, wenn die Anwendung die Inhalte morgen auf andere Art und Weise erzeugt.
Capybara erfüllt diese Erwartungshaltung. Eine ganze Reihe andere Test-Frameworks für Web-Anwendungen sind weit davon entfernt, insbesondere die Frameworks, die auf einer niedrigeren Abstraktionsstufe operieren, wie zum Beispiel Selenium. Wenn der Test-Code mit Anweisungen der Art waitForXyz
oder sogar dem haarsträubenden (weil willkürlichen) sleep 2s
übersät ist, benutzt man vermutlich das falsche Test-Framework.
Weitere Cucumber-Features und Scenarios
Wir könnten nun noch eine ganze Menge weitere Features und Scenarios für den Audio Book Collection Manager schreiben. Der Branch master
des Beispiel-Cucumber-Projekts enthält weitere Features, zum Beispiel für das Hinzufügen eines neuen Hörbuchs oder zum Anzeigen detaillierterer Informationen zu einem Eintrag. Mit git checkout master
kann man sich diese anschauen. Wer das Tutorial bis hierhin durchgearbeitet hat, dem werden in den zusätzlichen Features und Step-Files wohl keine allzu großen Überraschungen mehr begegnen.
Interessanter wäre es ggf., auf eigene Faust ein paar Cucumber-Features zu schreiben. Wie wäre es mit einem Feature für das Löschen von Hörbüchern? Oder für die Anzeige des CD-Covers eines Hörbuchs? Die entsprechende Funktionalität ist in der Anwendung bereits implementiert, es fehlt nur noch der Cucumber-Test. (Das Cover-Bild wird in der Detail-Ansicht automatisch angezeigt, falls eine ASIN eingetragen ist und amazon.com ein Bild für diese ASIN liefert).
Fazit
Damit endet unser kleiner Ausflug in die Welt von Cucumber und Capybara. Dieses Tutorial zeigt natürlich nur einen kleinen Ausschnitt von dem, was möglich ist. Ich hoffe, es wurde trotzdem deutlich, dass diese Kombination recht mächtig ist und sich damit sehr elegante und lesbare Akzeptanztests schreiben lassen.
Credits
Ein Teil des Setup-Codes (insbesondere das Umschalten zwischen Poltergeist/PhantomJS und Selenium WebDriver/Firefox durch eine Umgebungsvariable) wurde von Ruby-Guru Michael Schuerig geschrieben. Durch Michael bin auch zum ersten Mal mit Capybara und Poltergeist in Berührung gekommen.
Weitere Beiträge
von Bastian Krol
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Bastian Krol
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.