Steven has posted 36 posts at DZone. View Full User Profile

easyb: Introducing Conversational Unit Tests for Java

02.07.2008
| 24026 views |
  • submit to reddit

Andrew Glover is co-author of Groovy in Action and wrote a test framework called easyb. The new framework promotes a more "conversational" approach to unit testing. DZone's Steven Devijver caught up with Andrew to hear his thoughts on Test-Driven Development, stories and behavior.

Q: Hey Andrew, you're co-author of Groovy in Action and author of the easyb test framework. What is easyb for?

A: easyb is story verification framework built in the spirit of behavior driven development. It's written with mostly Groovy and made to work with Groovy and Java. With easyb, you can write stories that help validate applications-- say for example, a Stack. With Stacks you can push and pop values-- the push method should place things into some collection and the pop method should remove them, right? Using easyb, you could craft a story, which is essentially a series of scenarios, which read as

given some context
when something happens
then something else should happen

With that format, you could write some scenarios like "pop is called on the stack with one value" or "peek is called on a stack with one value"-- you can then code a particular scenario with givens, whens, and thens like this:

scenario "pop is called on stack with one value", {

given "an empty stack with foo", {
stack = new Stack()
stack.push("foo")
}

when "pop is called", {
popVal = stack.pop()
}

then "foo should be returned", {
popVal.shouldBe "foo"
}

and

then "the stack should be empty", {
stack.empty.shouldBe true
}
}

easyb supports a flexible verification syntax too-- see the shouldBe call that's auto-magically wired to everything within the context of a scenario? You could use shouldBeEqual, shouldBeEqualTo, shouldEqual and of course the negatives of that as well, like shouldNotBe, etc, etc.

The intent is to create executable documentation-- someone else, say a customer or business analyst could conceivably write the text of a story and then a developer can then implement things like I did above. Incidentally, when running this particular scenario (which is one of a few found in one story), you can produce a report that describes which stories were run that looks something like this:

Story: single value stack
scenario pop is called on stack with one value
given an empty stack with foo
when pop is called
then foo should be returned
then the stack should be empty

Q: Is easyb intended for unit testing? Or can it also be used for integration testing?

A: Yes and Yes! It's entirely up to you how you use it-- out of the box, the framework comes with a plug-in that supports database management via DbUnit, so there is a lot of support for integration testing. For instance, if you find that a particular story requires some prerequisite data, you can put that data in a database via the database_model call, which takes standard JDBC connection information (URL, user name, driver, etc) and then a String representation of DbUnit's standard FlatXmlDataSet type. So for example, in a given clause you can seed a database like so:

given "the database is properly seeded", {
database_model("org.hsqldb.jdbcDriver",
"jdbc:hsqldb:hsql://127.0.0.1", "sa", ""){
return new File("./src/conf/seed.xml").text
}
}

That makes integration testing easy, doesn't it? The DbUnit plug-in is a separate jar file you can download from the easyb website-- just ensure you have that jar in your classpath and easyb will find it if you invoke the database_model call. Our intent with the plug-ins is to have various ones that facilitate higher level testing, so its feasible that there'll be a Selenium plug-in, for instance.

I tend to find that using a story format even at the object (aka unit testing level) helps drive things in a true TTD fashion-- for instance, take the classic Money example from the JUnit Test Infected example-- given an add method, you could write a unit test (in JUnit) like so:

public class MoneyTest extends TestCase {

public void testSimpleAdd() {
Money m12CHF= new Money(12, "CHF");
Money m14CHF= new Money(14, "CHF");
Money expected= new Money(26, "CHF");
Money result= m12CHF.add(m14CHF);
Assert.assertTrue(expected.equals(result));
}
}

Writing the same code in easyb is something like this:

scenario "two moneys of the same currency are added", {

given "one money object is added to another", {
total = new Money(12, "CHF").add(new Money(14, "CHF"))
}

then "the total amount should be the sum of the two", {
total.amount().shouldBe 26
}

}

Note though that in the process of writing a simple story, I was forced to think about scenarios (before I typed a line of code) and in doing so, I quickly found myself thinking about other scenarios-- like two Money objects of different currencies. JUnit doesn't stop you from thinking that way either, but I find that the format of story almost begs it upfront.

Q: What advantages does easyb give to developers?

A: It's easy! Seriously though, easyb forces you think about behavior--- about how things should work and then allows you to express those expectations in a natural manner-- order.getPrice().shouldBe "$56" instead of assert this and that.

Stories facilitate collaboration too-- they're a mechanism to bridge development and stakeholders, much like Fit and Fitnesse are intended to do. Plus, easyb is fun! The story DSL and the expectation framework are pretty fun to use-- you can chain expectations quickly too, such as

var.shouldNotBe null
and
var.length().shouldEqual 6

The lack of parenthesizes and use of spaces makes that easy to code and easy to read.

Q: What made you decide to write easyb in Groovy and not another dynamic language?

A: Ruby already has RSpec, which is an excellent framework and I wanted to make something like that available for the Java world-- Groovy was a natural choice for me as I'm fairly conversant in it. Bias aside, creating DSLs in Groovy is unbelievably simple-- I also had the luxury of coding the initial prototype with Venkat Subramaniam and Jeff Brown, who are amazingly talented Groovy developers.

Q: According to you, is easyb capable of replacing the regular unit testing frameworks like JUnit or TestNG on development projects?

A: You certainly could if you had strong feelings about it, but TestNG (and JUnit 4) have some compelling features! TestNG, for instance, has phenomenal parametric testing and supports parallel testing, test groups, etc. These are mature, well thought-out frameworks that offer some great features that shouldn't be overlooked. I still use both frameworks where appropriate and encourage people to do the same.

Q: Is there integration with JUnit or TestNG so that easyb stories become part of test suites and continuous integration?

A: At this point there is no integration with JUnit or TestNG; however, you can certainly run your easyb stories via Ant (a Maven plug-in is forthcoming) like so:

<easyb failureProperty="easyb.failed">
<classpath>
<path refid="build.classpath" />

<pathelement path="target/classes" />
</classpath>

<report location="target/story.txt" format="txtstory" />

<behaviors dir="behavior">
<include name="**/*Story.groovy" />
</behaviors>
</easyb>

Thus, you can easily set up a CI process that kicks off easyb stories on a scheduled basis or when ever code changes.

Q: Does easyb have IDE integration?

A: Not at this moment, unfortunately. It is run via a Java class, so you can easily create a profile in Eclipse to run stories.

Thanks for the excellent interview Andrew!

 

Published at DZone with permission of its author, Steven Devijver.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Wayne Simacek replied on Thu, 2010/05/27 - 10:47am

I just started using easyB as a plugin for IntelliJ to write pending stories. Now I'm excited to take it to the next level and start true BDD.

Lucifer Williams replied on Thu, 2012/11/15 - 4:46pm

With Stacks you can push and pop values-- the push method of dms document management should place things into some collection and the pop method should remove them, right? Using easyb, you could craft a story, which is essentially a series of scenarios, which read as

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.