Groovy language is more and more riveting the attention of people enthusiastic about Java technologies, which is confirmed by the articles published in Java exPress. Simplicity and syntax clarity are its unquestionable advantages, both of which allow to improve productivity and let you avoid monotonous boilerplate code, so well known to all Java users.
In this article I would like to present you very interesting and useful Groovy-based tool, delighting with its simplicity and versatility in tests, and, which is most important, allowing you to write tests in accordance with the concept of behaviour-driven development(BDD).
Prior to introducing easyb it's worth to say a few words about behaviour-driven development itself, which is gaining popularity. On what assumptions does it work ? How does it differ from test-driven development? What Java tools allows you to write tests in keeping with BDD? After reading this article not only will you have expanded your IT-jargon dictionary with a new trendy acronym, but also you'll be able to answer all above questions.
To depict the concept of BDD I'll use a simple example. Let's say, that we're organizing a Java-related technologies conference and we need to create a registration module. Obviously, in order to encourage would-be participants we need to offer some discounts. To simplify our example let's assume, that the price of a standing ticket is 100 PLN. So, let's get down to work! We start (as always, don't we) from test:
@Test public void testConferenceDiscount() { Participant p = new Participant(); p.setJavaUserGroupMember(true); RegistrationService registrationService = new RegistrationService(); PaymentDetails paymentDetails = registrationService.register(participant); assertEquals(80.0, paymentDetails.getPrice()); }
You don't need a lot of test writing experience to notice, that above code is far from perfect. Firstly, it's imprecise. The method's name isn't meaningful at all. If we encountered a bug, in order to find the details about the conditions of applying a discount, we would have to read whole the body of this test method. In that particular example it isn't such a challenge, but for sure most of you not once have encountered much more "extended" tests, which you had to analyse. What's more, writing tests, especially when you start with test-driven development, very often you're asking yourself: "What exactly should I test?". Not rarely do we focus mostly on implementation details of classes, whose behaviour we want to verify, than on actual requirements they should satisfy. Such and similar problems is behaviour-driven development concept trying to fight with.
Behaviour-driven development, defined by Dan North in "Better Software" magazine (03.2006), is an approach focusing firstly at the requirements that a tested application component should fulfil. It's derived from test-driven development. The main difference is that BDD is firstly focusing on verification of a particular requirement of the application. Each test(scenario) is being created in such a way so it describes a particular behaviour of the system. One of the demands (which appeared also in mentioned above article) is choosing for methods such names, which are de facto sentences describing our expectations. In our case we could rename our method to:
@Test public void shouldReceiveTwentyPercentOfDiscountIfRecipientIsJUGMember () { ... }
Our approach of writing tests should have following schema:
preconditions defining,
executing an action that we are testing,
checking results with the expected values,
to say it in a bit more descriptive way:
given some specified preconditions;
when we execute an action on the component we're testing;
then we should get expected results.
The final version of our test, following BDD standards, could look like that:
@Test public void shouldReceiveTwentyPercentOfDiscountIfRecipientIsJUGMember () { // given Participant p = new Participant(); p.setJavaUserGroupMember(true); // when RegistrationService registrationService = new RegistrationService(); PaymentDetails paymentDetails = registrationService.register(participant); // then assertEquals(80.0, paymentDetails.getPrice()); }
Unquestionably, this template improves readability of test and makes it easier to be understood. I saw it first time during Szczepan Faber’s talk on GeeCON conference. But, it’s just a convention and without a discipline within a team can be forgotten really fast. Fortunately, there are libraries supporting behaviour-driven development technique and allowing us to think about tests as of real requirements of the system. One of them is easyb.
Easyb is a made upon Groovy DSL (domain specific language) offering constructions promoted by BDD. Primary terms are scenarios and stories, which are a set of scenarios. Let’s go back to our test and try to specify a requirement related to registration module in our application:
Users being JUG members should receive 20% discount while registering.
given a JUG member user;
when he registers to conference;
then he should get 20% discount.
In easyb our scenario will look like depicted below:
scenario "Java User Group members should receive 20% discount", { given "participant is a JUG member" when "he registers for the conference" then "he should receive 20% discount" }
As easyb is a Groovy, so it's possible to use any Java classes, which also means – to test them. The second very important feature of that language are closures, which make our code more concise and let above scenario to be an executable documentation. The final version of our scenario could then look like presented below.
scenario "Java User Group members should receive 20% discount", { given "participant is a JUG member", { p = new Participant() p.setJavaUserGroupMember(true) } when "he registers for the conference", { registrationService = new RegistrationService() paymentDetails = registrationService.register(participant) } then "he should receive 20% discount", { paymentDetails.price.shouldBe 80.0 } }
What's more, test in unimplemented form is also executable. In the report generated by easyb it'll be standing as "pending".
Running user registration story (UserRegistrationStory.groovy) Scenarios run: 1, Failures: 0, Pending: 1, Time elapsed: 0.89 sec 1 behavior ran (including 1 pending behavior) with no failures
Another interesting feature of easyb are the verification methods of results, looking as if they were written in natural language. Comparing the standard approach:
assertEquals(80.0, paymentDetails.getPrice());
with the one offered by easyb it's quite obvious which one is more understandable, and everybody would be convinced about that.
paymentDetails.price.shouldBe 80.0
Easyb offers the whole bunch of methods that can be used for scenario result checking. So, for comparing two objects there are:
shouldBe / shouldNotBe shouldEqual / shouldNotEqual
we can compare their values:
shouldBeGreaterThan shouldBeLessThan shouldStartWith shouldEndWith
so can we verify their types:
shouldBeA / shouldNotBeA shouldBeAn / shouldNotBeAn
there are also convenient methods for checking collections equality.
shouldHave / shouldNotHave
It would be a huge injustice and abuse if we didn’t mention about such Java libraries like Hamcrest or FEST-Assert, both of which give means of verification similar to natural language.
As mentioned before, tests written with easyb have a form of executable but simplified documentation. Thus, while executing scenarios we can generate reports based on them. Those reports can act as parts of system documentation. We are given two possibilities in here: either we can choose a simple text format or a HTML page. It can contain informations as depicted on pictures 1 and 2, but also detail information about errors that appeared while executing.
Rys 1.
Rys 2.
1 scenario executed successfully. Story: Users registration scenario Java User Group members should receive 20% discount given participant is a JUG member when he registers for the conference then he should receive 20% discount
Scenarios created with easyb have simple and easy to understand structure. So it’s tempting to get to making them those team members who are not necessary working everyday with code. But, in the era of such tools like FitNesse or Concordion it seems that non-technical people rather wouldn’t be eager to write requirements in easyb. Nevertheless, recently can be heared rumours about development of application called Easiness, which is supposed to please expectations of such users.
Without such tools like IDEs or continuous integration servers we can’t fully use the advantages that reliable tests can offer us. In moment of writing this article there is an IntelliJ IDEA plugin available and, for some time, for Eclipse too. Besides, we can run easyb scenarios with Apache Ant, Maven or from command line.
Alternatives
Obviously, easyb is not the only one working on JVM tool for writing tests according to behaviour-driven development. Here is the list of a few others:
In this article I've presented very interesting alternative used to writing tests, which is a behaviour-driven development and also easyb. It allows you to concentrate on requirements and write tests in such a way so they could be easy to understand even for people without IT experience. Of course, possibilities of scenario implementation provided by easyb are much wider than described. In this article only most important features and functions have been introduced. I keenly recommend to visit sites linked in the section Sources, but, what's more important, to experiment oneself. Very good use, which emphasize advantages of easyb, are user interface functional tests. Thanks to scenarios the description of interaction between user and application looks very natural. In pair with some convenient library emulating actions of user with web browser, easyb is really an interesting solution, but this is a subject for another article.
http://dannorth.net/introducing-bdd - an introduction to behaviour-driven development
http://easyb.org/ - the main page of easyb project
http://parleys.com/display/PARLEYS/Home#talk=28573704 – presentation about easyb from Devoxx conference
http://fitnesse.org/ - web page of FitNesse project
http://code.google.com/p/givwenzen/ - web page of GivWenZen project
http://www.concordion.org/ - web page of Concordion project
http://code.google.com/p/specs/ - web page of Specs project
http://groovy.codehaus.org/Using+GSpec+with+Groovy – an introduction to Spec
http://jbehave.org/ - projekt JBehave
http://wiki.github.com/aslakhellesoy/cuke4duke - web page of Cuke4Duke project
http://code.google.com/p/hamcrest/ - Hamcrest lib
http://fest.easytesting.org/assert/wiki - FEST-Assert lib
Translated by: Mirosław Pluta (Pluta.Miroslaw@gmail.com)
Source: http://www.javaexpress.pl/article/show/Notatki_o_testowaniu_Behaviourdriven_development_z_easyb