Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Acceptance Testing with Cucumber

Bart Bakker
February 10, 2014

Acceptance Testing with Cucumber

Almost all software gets acceptance tested in one way or another. Often this is a manual process, sometimes these tests are automated by programmers. Cucumber provides a format language for describing acceptance tests. Why do we need a different language? And what could be the benefits of using this language?

To answer these questions we’ll take a deeper look at some of the real problems we face every day in software development. Together we’ll find an answer to the actual meaning of acceptance testing.

In the second part of this presentation we’ll get a basic understanding of Bahavior-Driven Development (BDD), and follow this process to create a set of Cucumber acceptance tests for a Fibonacci Sequence, and develop the feature following these tests.

Bart Bakker

February 10, 2014
Tweet

More Decks by Bart Bakker

Other Decks in Programming

Transcript

  1. Given a Fibonacci Sequence When I query the sequence at

    index 5 Then the number I get is 8
  2. Discount Rules I II III IV V Formula $ 1

    1 * 8 8.00 1 1 2 * 8 * 0.95 15.20 1 1 1 3 * 8 * 0.9 21.60 1 1 1 1 4 * 8 * 0.8 25.60 1 1 1 1 1 5 * 8 * 0.75 30.00 2 2 * 8 16.00 2 1 2 * 8 * 0.95 + 1 * 8 23.20 2 2 2 1 1 4 * 8 * 0.8 + 4 * 8 * 0.8 51.20
  3. Discount Rules I II III IV V Formula $ 1

    1 * 8 8.00 1 1 2 * 8 * 0.95 15.20 1 1 1 3 * 8 * 0.9 21.60 1 1 1 1 4 * 8 * 0.8 25.60 1 1 1 1 1 5 * 8 * 0.75 30.00 2 2 * 8 16.00 2 1 2 * 8 * 0.95 + 1 * 8 23.20 2 2 2 1 1 4 * 8 * 0.8 + 4 * 8 * 0.8 51.20 Optimal Customer Discount
  4. Scenario: buy one book from the series
 
 When I

    buy 1 copy of “Harry Potter I”
 Then I must pay $8 Scenario: buy two books from the series
 
 When I buy 1 copy of “Harry Potter I” And I buy 1 copy of “Harry Potter II” Then I must pay $15.20
  5. Scenario Outline: buy Harry Potter books
 When I buy <I>

    copies of “Harry Potter I”
 And I buy <II> copies of “Harry Potter II”
 And I buy <III> copies of “Harry Potter III”
 And I buy <IV> copies of “Harry Potter IV”
 And I buy <V> copies of “Harry Potter V”
 Then I must pay $<Total> Examples:
 | I | II | III | IV | V | Total | | 1 | 0 | 0 | 0 | 0 | 8.00 | | 1 | 1 | 0 | 0 | 0 | 15.20 | # .. | 2 | 1 | 0 | 0 | 0 | 23.20 | | 2 | 2 | 2 | 1 | 1 | 51.20 |
  6. UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ! 9 Scenarios (9 undefined) 54 Steps (54 undefined)

    0m0.000s ! ! You can implement missing steps with the snippets below: ! @When("^I buy (\\d+) copies of \"([^\"]*)\"$") public void I_buy_copies_of(int arg1, String arg2) throws Throwable { // Express the Regexp above with the code you wish you had throw new PendingException(); } ! @Then("^I must pay \\$(\\d+).(\\d+)$") public void I_must_pay_$_(int arg1, int arg2) throws Throwable { // Express the Regexp above with the code you wish you had throw new PendingException(); }
  7. UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU ! 9 Scenarios (9 undefined) 54 Steps (54 undefined)

    0m0.000s ! ! You can implement missing steps with the snippets below: ! @When(“^I buy (\\d+) copies of \"([^\"]*)\"$") public void I_buy_copies_of(int arg1, String arg2) throws Throwable { // Express the Regexp above with the code you wish you had throw new PendingException(); } ! @Then("^I must pay \\$(\\d+).(\\d+)$") public void I_must_pay_$_(int arg1, int arg2) throws Throwable { // Express the Regexp above with the code you wish you had throw new PendingException(); }
  8. P-----P-----P-----P-----P-----P-----P-----P-----P----- ! 9 Scenarios (9 pending) 54 Steps (45 skipped,

    9 pending) 0m0.336s ! cucumber.api.PendingException: TODO: implement me at com.github.bjpbakker.potter.cucumber.DiscountStepdefs.I_buy_copies_of(Discou ntStepdefs.java:11) at ✽.When I buy 1 copies of "Harry Potter I"(features/discount.feature: 16)
  9. public class DiscountStepdefs { private List<Book> cart = new LinkedList<>();

    ! @When("^I buy (\\d+) copies of \”([^\”]*)\"$") public void I_buy_copies_of(int numberOfCopies, String title) { Book book = bookByTitle(title) .orElseThrow(() -> new UnknownTitle(title)); range(0, numberOfCopies) .forEach(n -> this.cart.add(book)); } ! // .. } ! class Book { // .. }
  10. public class DiscountStepdefs { private List<Book> cart = new LinkedList<>();

    ! @When("^I buy (\\d+) copies of \”([^\”]*)\"$") public void I_buy_copies_of(int numberOfCopies, String title) { Book book = bookByTitle(title) .orElseThrow(() -> new UnknownTitle(title)); range(0, numberOfCopies) .forEach(n -> this.cart.add(book)); } ! @Then("^I must pay \\$(\\d+.?\\d*)$") public void I_must_pay_$_(float amount) { Long expected = Float.valueOf(amount * 100).longValue(); ShoppingCart shoppingCart = new ShoppingCart(this.cart); Long total = shoppingCart.calculateTotal(); assertThat(total, is(expected)); } ! // .. } ! class Book { .. } ! class ShoppingCart { public ShoppingCart(List<Book> cart) {} public Long calculateTotal() { return -1L; } }
  11. .....F.....F.....F.....F.....F.....F.....F.....F.....F ! 9 Scenarios (9 failed) 54 Steps (9 failed,

    45 passed) 0m0.247s ! java.lang.AssertionError: Expected: is <800L> but: was <-1L> at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8) at com.github.bjpbakker.potter.cucumber.DiscountStepdefs.I_must_pay_ $_(DiscountStepdefs.java:30) at ✽.Then I must pay $8.00(features/discount.feature:21) ! java.lang.AssertionError: Expected: is <1520L> but: was <-1L> at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:8) at com.github.bjpbakker.potter.cucumber.DiscountStepdefs.I_must_pay_ $_(DiscountStepdefs.java:30) at ✽.Then I must pay $15.20(features/discount.feature:21) ! java.lang.AssertionError: Expected: is <2160L> but: was <-1L>
  12. public class ShoppingCart { public Long calculateTotal() { return total(new

    Series(this.cart)); } ! private Long total(Series series) { if (series.isEmpty()) { return 0L; } else { Set<Book> books = takeOptimalDiscount(series); Long subtotal = subtotal(books, discount(books.size())); return subtotal + total(series.drop(books)); } } ! // .. } ! public class Series { .. } public class Book { .. }
  13. Scenario Outline: buy Harry Potter books
 When I buy <I>

    copies of “Harry Potter I”
 And I buy <II> copies of “Harry Potter II”
 And I buy <III> copies of “Harry Potter III”
 And I buy <IV> copies of “Harry Potter IV”
 And I buy <V> copies of “Harry Potter V”
 Then I must pay $<Total> Examples:
 | I | II | III | IV | V | Total | | 1 | 0 | 0 | 0 | 0 | 8.00 | | 1 | 1 | 0 | 0 | 0 | 15.20 | # .. | 2 | 1 | 0 | 0 | 0 | 23.20 | | 2 | 2 | 2 | 1 | 1 | 51.20 |