Monday, November 9, 2009

Getting started with the easyb plugin for BDD in Grails

One of the more exciting things I've learned about recently is doing behavior driven development (BDD) with a framework called easyb. Easyb allows you to test your system by defining behavior in stories and specifications in a way that allows your "non-developer" stakeholders to understand them relatively easily. I also find that it helps me think more clearly about what my systems should actually be doing and how the pieces should interact. Like I said, I'm really excited by it, and I really wanted to start incorporating easyb where I can. Since I've been doing a ton of Grails work lately, naturally I wanted to try to incorporate it into my Grails workflow. Fortunately, there's a plugin for that, the Grails easyb plugin.

The first step in doing BDD with easyb in Grails is, of course, to install the plugin, and you do that in the same way you install any other Grails plugin: in your project directory, issue the command "grails install-plugin easyb". After all the noise of starting Grails and downloading the plugin artifact, you'll see:

Plug-in provides the following new scripts:
------------------------------------------
grails easyb-test


Now we can mix easyb stories and specifications in with the usual Grails tests and run them using "grails easyb-test" command. Note, however, that at this point, to execute both your easyb and usual Grails tests, you have to run two commands, both "grails test-app" and "grails easyb-test": just running the normal "test-app" won't also execute the easyb tests, and running the easyb tests won't also execute the normal tests.

So let's say I'm working with an application that takes dry cleaning orders and I want to test the behavior of the service that creates orders when a customer drops of some suits to be dry cleaned. Assuming I have a class called DropOffService, I'll create a new file in the test/unit directory, calling it either DropOffService.story or DropOffServiceStory.groovy (either will work).

Now I can define the behavior I want in the story file. I won't go in-depth on the details of writing easyb stories since there's good documentation on the easyb site for that, but the short form is that I create scenarios with given conditions, some event that occurs, and a pre-defined outcome. To test our service's behavior, I might define the story like this:

scenario "customer drops off suits", {
given "a drop-off service"
and "a customer with suits"
when "the customer drops off the suits"
then "the service should generate a new order"
}


At this point, I haven't actually written any code that will exercise the service, but I can still run "grails easyb-test". When I do, the plugin looks for valid easyb stories and specifications, runs them, and generates reports in the test/reports directory. The easyb plugin generates both text and html reports just like the standard Grails tests; however, it also produces XML output, too, potentially useful for reporting in something like a continuous integration system. Unlike the standard Grails reporting, instead of getting a file for each test class, the easyb plugin generates a report for each *type* of test. So we end up with a reports listing that looks like this:

test/reports/html:
easyb-functional.html easyb_img04.jpg easyb_report.css
easyb_img01.gif easyb_img05.jpg easyb_spacer.gif
easyb_img02.jpg easyb_img06.jpg easyb-unit.html
easyb_img03.jpg easyb-integration.html prototype.js

test/reports/plain:
specifications-functional.txt stories-functional.txt
specifications-integration.txt stories-integration.txt
specifications-unit.txt stories-unit.txt

test/reports/xml:
easyb-functional.xml easyb-integration.xml easyb-unit.xml


If we actually look at the reports, we'll see that the single scenario I've written has a result of "pending" since I haven't actually implemented any code to exercise the drop-off service. At the point where I actually *do* something in the story, the result will change depending on whether or not the scenario produces the outcome I'm expecting.

So there's the basics of using easyb with Grails. There's definitely more to explore beyond this simple example (testing controllers, using dependency injection, and such), and I'll do that in future postings.

8 comments:

Lim Chee Kin said...

Hi Jeffrey,

Thanks for sharing a great article. I believe you will interested on the related topic posted by me few months ago.

"Behavior driven development: Generating Groovy EasyB Story with Selenium IDE" at following URL:
http://limcheekin.blogspot.com/2009/07/behavior-driven-development-generating.html

Please feel free to comment.

Jeffrey Erikson said...

Thanks! Another of my colleagues is looking at using easyb and Selenium with our Grails app . . . I'll be pointing him to your post. Thanks again.

Brandon said...

Hey Jeffrey, Great post! Very useful for where I'm at in a project right now.

The part that has me stumped is dependency injection inside EasyB stories or specifications.... is there a chance you've figured that out and could help me out? Or at least point me in the right direction?

Thanks! Brandon

Jeffrey Erikson said...

Brandon, glad you found it useful. Dependency injection is somewhat roundabout . . . check out my post here to see what I've done to make it work.

Brandon said...

Jeffrey, Thanks again. That post is perfect and I think I'll use your plugin. Seems like that should be published somewhere, or a part of the easyb plugin for grails.

Jeffrey Erikson said...

Again, I'm glad you found it useful . . . I've actually been talking with the easyb folks, and they, too, think the plugin might be a useful addition to the easyb Grails plugin. We'll see what we can do.

RH said...

Hey Jeffrey,

Thank you for putting this all together. I would like to request you:

1. What version of grails are you using?
2. Could you please post your sample app so we can use it as an example?

Thanks,
Ravi

Anonymous said...

Hi there,

I have been to add scenarios and run them successfully. However, I cannot see any HTML reports generated.

My story.groovy file is located under the behaviour directory.

Please let me know if I am missing something here.