Sep 17 2009

Using JDave: A quick introduction to specs framework

Category: bdd,java,tutorialgiordano scalzo @ 5:13 pm

As second Bdd engine to try, I choose JDave, a specification oriented engine.
JBehave is, instead, user-stories-oriented: the difference is very subtle and I’m not sure I caught it completely ;-) .
Anyway, JDaveis inspired by RSpec, at the moment the most used bdd engine, so I thought it deserved a try.
In order to compare JDave with JBehave, I implemented the StringTemplater kata, as in my previous post.

Installing JDave

After creating a java project, I simply downloaded the last version of JDave and extracted all jar in lib directory of my project:

JDave Jars

They are a lot of jars, and I’m sure I won’t use all of them, but it’s just a try so it doesn’t deserve the time to filter only the used ones.

JBehave is a story runner, so each scenario must be written as:

Given something
When something happens
Then this happens

Instead, JDave is a specification engine and each scenario show a behavior of a class:

AThingIWantToWrite
  - ShouldDoThis
  - ShouldDoThat
  - ShouldntDoThat

In other words, JBehave is similar to Cucumber, JDave is similar to RSpec.

Writing a specification is really straightforward:
first of all, we create a Specification object, passing the object we want to write; then we create a serie of inner classes:

@RunWith(JDaveRunner.class)
public class StringTemplaterSpec extends Specification<ThingIWantToWrite> {
	public class AThingIWantToWrite {
		public void ShouldDoThis() {
		}
		public void ShouldDoThat() {
		}
        }
   ...
}

As JBehave, JDave is a wrapper built over JUnit, so we can use our Ide integration to run the specifications.
That’s it!

The code

As in JBehave try, I implemented the same scenarios as in Corey Haines Video:

package biz.scalzo.kata.stringtemplater.jdave;

import org.junit.runner.RunWith;

import jdave.Specification;
import jdave.junit4.JDaveRunner;

@RunWith(JDaveRunner.class)
public class StringTemplaterSpec extends Specification<StringTemplater> {
	public class AStringTemplater {
		private StringTemplater stringTemplater;

		public void create() {
			stringTemplater = new StringTemplater();
		}

		public void shouldReturnEmptyWhenAnEmptyStringIsPassed() {
			specify(stringTemplater.replace(""), must.equal(""));
		}

		public void shouldReturnTheOriginalStringWhenNoMarkersArePassed() {
			specify(stringTemplater.replace("original string"), must.equal("original string"));
		}

		public void shouldReplaceAToken() {
			specify(stringTemplater.replace("Hello, $name","name: giordano"),
					must.equal("Hello, giordano"));
		}

		public void shouldReplaceTwoTokens() {
			specify(stringTemplater.replace("Hello, $name, how a $attitude day","name: giordano, attitude:  wonderful"),
					must.equal("Hello, giordano, how a wonderful day"));
		}

		public void shouldRemoveNotProvidedMarkers() {
			specify(stringTemplater.replace("Hello, $name, how a $attitude day","name: giordano"),
					must.equal("Hello, giordano, how a  day"));
		}
	}

}

The Junit view of Eclipse is very explicative of the behaviors of StringTemplater:
JUnit View

For sake of completeness, this is the final implementation of StringTemplater:

package biz.scalzo.kata.stringtemplater.jdave;

import java.util.Arrays;
import java.util.Iterator;

public class StringTemplater {

	public String replace(String stringToReplace) {
		return replace(stringToReplace, "");
	}

	public String replace(String stringToReplace, String markers) {
		return replace(stringToReplace, initialIterator(markers));
	}

	private String[] tupla(String pair) {
		return pair.split(":");
	}

	private Iterator<String> initialIterator(String markers) {
		return Arrays.asList(markers.split(",")).iterator();
	}

	private String replace(String stringToReplace, Iterator<String> markers) {
		if (!markers.hasNext())
			return stringToReplace;
		String[] pair = tupla(markers.next());
		String newString = stringToReplace.replace(name(pair), value(pair));
		return replaceEmptyMarkers(replace(newString, markers));
	}

	private String replaceEmptyMarkers(String replace) {
		return replace.replaceAll("\\$\\w+", "");
	}

	private String value(String[] pair) {
		return (pair.length != 2) ? "" : pair[1].trim();
	}

	private String name(String[] pair) {
		if (pair.length != 2)
			return "";
		return "$" + pair[0].trim();
	}
}

Conclusions

JDave is very easy to learn and the specifications written throught it are very complete and expressive.
If I have to make a choice, I liked slightly more JDave, but I think are just two tools: BDD is a way to think, not a framework or an engine to use.

In conclusions, I believe JBehave and JDave could be used together, the former to describe the user stories, at user level, the latter to describe the behaviors of the classes, at developer level.

Technorati Tags: , , ,

Tags: , , ,

  • http://giordano.scalzo.biz/2009/09/18/extreme-refactoring-or-is-guard-clause-considered-harmful/ Int21 » Extreme Refactoring or Is Guard clause Considered harmful?

    [...] the JDave try, the focus was on Bdd side of the exercise, but, nonetheless, the StringTemplater’s code was [...]