Saturday, October 24, 2009

JExample: Defining Dependencies Between Unit Tests

I can't remember how I found it, but I've been meaning to investigate JExample for some time. To quote the project page, "JExample is a small framework to write unit tests that depend on each other."

I've read a lot about whether or not this is a good idea, and a lot of people say your unit tests should be able to run independent of one another. If one test fails, preventing the others to run, you might not catch all the failures in a complete run of your test suite. One test will fail, you'll fix it, and then you will be presented with a failure in another test.

After reading the project page, I can see where the project authors are coming from. They use a Stack as an example. Why you should run a test that adds three items to a Stack, when adding one item fails, or adding an item to an empty stack would fail? Maybe there's something to having dependencies between your tests. I'm not going to recommend either approach, for fear of starting another debate, but I would saying having the dependent approach in your toolbox could be useful depending on your particular testing situation.

The jar can be downloaded here: JExample Latest. Since I'm a Maven fan, I'll include how I added the jar to my Maven repository at the end of this post.

I do not want to reproduce the example found on the project page here, so I'll add a twist by writing my sample project in Groovy to see if it plays nicely (as I type, I haven't started).

My test project will be very similar though, a Rolodex class that keeps a list of Contacts

The Rolodex and Contact classes:

  class Contact {
def name
def phone
def email
}

class Rolodex {
def contacts = []
def add(contact) { contacts << contact }
def remove(contact) { contacts >> contact }
def size() { contacts.size() }
}
The start of my test class without anything from JExample:
  import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory

class RolodexTest extends GroovyTestCase {

Log logger = LogFactory.getLog(getClass())
def rolodex

void setUp() { rolodex = new Rolodex() }

void test_initialized_rolodex() {
logger.info "Test initial Rolodex."
assertEquals "rolodex empty", 0, rolodex.size()
}

void test_adding_first_contact() {
logger.info "Adding Cosmo."
def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
}

void test_removing_first_contact() {
logger.info "Removing Cosmo."
def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
rolodex.remove contact
assertEquals "rolodex now empty", 0, rolodex.size()
}
}

In every test, I have to start with a newly constructed Rolodex. The first test may seem trivial. Do I really need to test a List starts empty? I say why not, but at the very least it will help demonstrate adding dependencies between the tests. The key here is the third test, which essentially duplicates the second by requiring that I add a Contact in order to remove it.

The dependency chain flows naturally out of the tests in the order they are written. I can't create a Rolodex with one contact unless I start with an empty one, and I can't remove a Contact unless I have one to remove.

Ok, I'm ready to try some JExample. After a little trial and error, it turns out I need JUnit 4 so I can use the @RunWith annotation. Since I'm using JUnit 4, I no longer need to extend GroovyTestCase. At this point, it seems I'm forced to use the @Test annotation as well since I'm using the @RunWith annotation.

I also added the @Before annotation to my setUp() method. I won't reproduce the code here to save space, but with or without the @Before annotation, the setUp() method isn't being called. To keep going, I'll add a call to each test method for now, as I think after I define my dependencies the need for the method will go away anyway.

The test class after these changes looks like:

  import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.junit.Test
import org.junit.runner.RunWith
import static org.junit.Assert.assertEquals
import ch.unibe.jexample.JExample
import ch.unibe.jexample.Given

@RunWith(JExample)
class RolodexTest extends GroovyTestCase {

Log logger = LogFactory.getLog(getClass())

def rolodex

void setUp() { rolodex = new Rolodex() }

@Test void test_initialized_rolodex() {
logger.info "Test initial Rolodex."
setUp()
assertEquals "rolodex empty", 0, rolodex.size()
}

@Test void test_adding_first_contact() {
logger.info "Adding Cosmo."
setUp()
def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
}

@Test void test_removing_first_contact() {
logger.info "Removing Cosmo."
setUp()
def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
rolodex.remove contact
assertEquals "rolodex now empty", 0, rolodex.size()
}
}

And the tests pass. Note that the third test for removing a Contact is run second. As JUnit does not guarantee tests are run in the order they are defined, this should not come as a surprise:

  Running prystasj.jexample.RolodexTest
INFO: Test initial Rolodex.
INFO: Removing Cosmo.
INFO: Adding Cosmo.
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.981 sec

Now to try and reach for my goal here by adding dependencies between my tests. The @Given annotation is used to define dependencies. To make things more readable within the annotations, I'm also going to remove the test prefix at the start of my methods.

Skipping a bit ahead in my discovery, I was hoping the definition of the dependency chain would allow me to remove the addition of the Contact in the third test. Before I get to that, here's the new test class:

  @RunWith(JExample)
class RolodexTest {

Log logger = LogFactory.getLog(getClass())

def rolodex
def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")

void setUpEmptyRolodex() { rolodex = new Rolodex() }

@Test
void initialized_rolodex() {
logger.info "Test initial Rolodex."
setUpEmptyRolodex()
def rolodex = new Rolodex()
assertEquals "rolodex empty", 0, rolodex.size()
}

@Given("initialized_rolodex")
void add_first_contact () {
logger.info "Adding Cosmo."
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
}

@Given("add_first_contact")
void remove_first_contact() {
logger.info "Removing Cosmo."
logger.info "Rolodex size: ${rolodex.size()}"
rolodex.remove contact
assertEquals "rolodex now empty", 0, rolodex.size()
}
}

My tests pass without the addition of good ol' Cosmo in remove_first_contact. It does appear however that the dependencies are executed again for every test which can be seen in the output below. I added an additional logging statement to help verify the Rolodex has a size of 1 at the start of remove_first_contact:

  Running prystasj.jexample.RolodexTest
INFO: Test initial Rolodex.
INFO: Test initial Rolodex.
INFO: Adding Cosmo.
INFO: Test initial Rolodex.
INFO: Adding Cosmo.
INFO: Removing Cosmo.
INFO: Rolodex size: 1
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 1.016 sec

Method initialize_rolodex is run three times. While this may be considered a turn off, but if you're tests are fast as they should be, it shouldn't pose a problem. This might be working to my benefit here as I'm storing my Rolodex as a property of my test class. Before I get to that, let's fail the addition test and verify the removal test is not run by changing Rolodex.add(contact) to do nothing:

    def add(contact) { // do nothing }

After add_first_contact fails, the dependant, remove_first_contact, is skipped:

  Running prystasj.jexample.RolodexTest
INFO: Test initial Rolodex.
INFO: Test initial Rolodex.
INFO: Adding Cosmo.
Tests run: 3, Failures: 0, Errors: 1, Skipped: 1, Time elapsed: 1.014 sec <<< FAILURE!

Results :

Tests in error:
add_first_contact(prystasj.jexample.RolodexTest)

Tests run: 3, Failures: 0, Errors: 1, Skipped: 1
It looks I accomplished what I was after. There's no need to test removal, if addition doesn't work.

Back to storing my Rolodex as a property. I originally decided that was necessary so I could ensure the same Rolodex was being used in each test, but I have not made use of one of the features of JExample: The result of a test method can be injected into a method dependent on it as a parameter.

Making use of this, I can remove the rolodex property, but then I also have to make the tests in which others depend on return the altered Rolodex:

  @RunWith(JExample)
class RolodexTest {

Log logger = LogFactory.getLog(getClass())

def contact = new Contact(name:"Cosmo", phone:"x6469", email:"cosmo@mail.next")

@Test
Rolodex initialized_rolodex() {
logger.info "Test initial Rolodex."
def rolodex = new Rolodex()
assertEquals "rolodex empty", 0, rolodex.size()
rolodex
}

@Given("initialized_rolodex")
Rolodex add_first_contact(Rolodex rolodex) {
logger.info "Adding Cosmo."
rolodex.add contact
assertEquals "contact added", 1, rolodex.size()
rolodex
}

@Given("add_first_contact")
def remove_first_contact(Rolodex rolodex) {
logger.info "Removing Cosmo."
logger.info "Rolodex size: ${rolodex.size()}"
rolodex.remove contact
assertEquals "rolodex now empty", 0, rolodex.size()
}
}

There are a couple things to note here, although I'm using Groovy here, I have to explicitly add the return type of Rolodex to my test methods to get things to play nicely with JExample. Methods initialize_rolodex and add_first_contact return the Rolodex for use in the next test, but I've omitted the optional return keyword.


Maven & JExample

I was unable to find JExample in remote Maven repository, so I needed to add it manually to my repository. This makes sense as the project appears to come from a research group and there doesn't appear to be an official release of sorts (at the time of this writing the latest jar is titled r378). I'll use r378 as my version number for my Maven dependency instead of a more conventional release or snapshot version number.

The coordinates I'll use:

  <dependency>
<groupId>jexample</groupId>
<artifactId>jexample</artifactId>
<version>r378</version>
</dependency>

I considered using a more descriptive groupId that reflected the Software Composition Group, but I decided to keep things simple.

Install the jar to your local repository with:

  $ mvn install:install-file \
-DgroupId=jexample \
-DartifactId=jexample \
-Dversion=r378 \
-Dpackaging=jar \
-Dfile=jexample-r378.jar \
-DgeneratePom=true

You then should be able to include the jar as a dependency in your project using the dependency coordinates found above.


Enlightenment: Terminal Transparency Workaround

With my recent e17 install, I was unable to set a transparent background in any of terminal programs (xfce terminal, gnome-terminal, mrxvt, etc.).

Well, not exactly, I was able to set a transparent background, but the effect didn't take.

I was able to correct it using Esetroot which is part of eterm-utils:

  $ Esetroot ~/Pictures/02043_conch_1280x960.jpg

This is more of a pseudo-transparency I believe. The picture you choose can be different than that used for your wallpaper, which I think is pretty cool.

Enlightenment e17 Install on Ubuntu 9.04

My desktop at home is not getting any younger, so I've been experimenting with some more lightweight desktops and window managers. I've tried (and recommend) e16, fvwm, and fvwm-crystal. My current Linux distrubtion is Xubuntu 9.04 and I also like the xfce desktop it provides. Maybe I just like everything.

After reading an article on Enlightenment in Linux Journal, I decided to give e17 a go.

First add the Enlightenment Repository to your sources list by opening your repository sources file with:

  $ sudo vi /etc/apt/sources.list
Add the following line:
  deb http://packages.enlightenment.org/ubuntu jaunty main extras

After adding the repository to your sources list, grab and add the repository key:

  $ wget http://packages.enlightenment.org/repo.key
$ sudo apt-key add repo.key
$ sudo apt-get update
And then install e17:
  $ sudo apt-get install e17 emodule-places \
emodule-tclock emodule-calendar

Once everything's installed, log out and at the log in screen click Session and select Enlightenment. Log back in and you'll be presented with a few setup pages (I selected the Standard setup and added Firefox and some more friends to application list). After setup, you should be good to go.

Tuesday, October 20, 2009

State vs. Method Parameters Lesson: IllegalStateExcpetions in a Mule Transformer

Proper use of state versus passing values around as parameters seems like a topic one should have down pretty well by some point in their programming careers, and therefore would not be the focus of too much attention as time goes on. I, however, have run into a situation recently where not paying enough attention to it has caused me some problems, which in hindsight make me feel like I was asking for them. To summarize, storing a variable as a property in class when I had no real reason to, even when it felt like it could be justified, proved to be troublesome.

The context of the problem involved my implementation of a Mule transformer, in which I had to implement a doTransform() method to transform a response from my service if the incoming service request had a specific property. The MuleMessage containing the property I'm interested in can be retrieved statically via the RequestContext and can be thought of to live through the lifetime of the request (i.e. until a response is sent).

Here's the code conceptually:
import org.mule.RequestContext
import org.mule.transformer.AbstractTransformer

class ResponseTransformer extends AbstractTransformer {

def muleMessage

@Override
protected Object doTransform(Object response, String encoding) {
try {
muleMessage = retrieveMuleMessage()
if (isSpecialResponseExpected()) {
def attributes = retrieveAttributesFromMessage()
response = makeMessageSpecial(response, attributes)
}
} catch(e) {
throw new TransformerException(this, e)
}
return response
}

def retrieveMuleMessage() { RequestContext.event.message }
boolean isSpecialResponseExpected() { muleMessage.getProperty("special") }
def retrieveAttributesFromMessage() { // do something with muleMessage property.. }
def makeResponseSpecial(response, attributes) { // transform response here ... }

}

There were no problems with the code as written when I was sending only one message at a time to my service. When the service had an opportunity to grab and process more than one message concurrently, however, I would consistently run into the following excpetion:

Caused by: java.lang.IllegalStateException: Only owner thread can write to message: Thread[asyncDelivery4,5,main]/Thread[asyncDelivery2,5,main]
at org.mule.transport.AbstractMessageAdapter.newException(AbstractMessageAdapter.java:619)
at org.mule.transport.AbstractMessageAdapter.checkMutable(AbstractMessageAdapter.java:605)
at org.mule.transport.AbstractMessageAdapter.assertAccess(AbstractMessageAdapter.java:546)
at org.mule.transport.AbstractMessageAdapter.setProperty(AbstractMessageAdapter.java:244)

Obviously Mule must not be very thread safe, right? I'm obviously not doing anything bad in my code to deserve this...

It's always easier to make something you had no hand in writing the first target for all your problems, but the truth of the matter is, by saving the retrieved Mule message in the muleMessage property, I am giving my transformer state.

Thinking functionally, the same request object and message properties should always map to or produce the same result. Therefore, the transformer could be implemented with one big method where all my code would reside, the doTransform() method here. On the other hand, with one conceptual way in and one way out, it couldn't hurt to just store the Mule message in a property instead of passing it around, right?

It seems however that transformers are instantiated in Mule as singletons (don't quote me on that), or at the very least I was not doing anything to ensure or verify they weren't. So by storing the message as a property, concurrent message threads were trying to access the same Mule message. The lesson here, (for me at least), is that I probably shouldn't store variables as properties unless I have a good reason to, when having state makes sense.

The revised code:

class ResponseTransformer extends AbstractTransformer {

@Override
protected Object doTransform(Object response, String encoding) {
try {
def muleMessage = retrieveMuleMessage()
if (isSpecialResponseExpected(muleMessage)) {
def attributes = retrieveAttributesFromMessage(muleMessage)
response = makeMessageSpecial(response, attributes)
}
} catch(e) {
throw new TransformerException(this, e)
}
return response
}

def retrieveMuleMessage() { RequestContext.event.message }

boolean isSpecialResponseExpected(muleMessage) { muleMessage.getProperty("special") }
def retrieveAttributesFromMessage(muleMessage) { // do something with muleMessage property.. }
def makeResponseSpecial(response, attributes) { // transform response here ... }
}

Passing the Mule message around is more functional, and could at the very least help me with my unit tests, where I wouldn't have to set the "state" of the transformer to test the methods that could have just as easily have another parameter in their signatures.

Saturday, October 3, 2009

XML Schema Validation with a Simple Groovy Script

I'm sure there are many methods for validating XML documents against schemas out there in Java-land. I decided I want a relatively simple way to do it using the command line method using a Groovy script. Since I'd also need to leverage some libraries to do the job, I thought I'd also try running my script from Maven, so once I defined the libraries I needed, I wouldn't have to worry about having to have them set up.

To start, I generated a simple project, selecting the basic GMaven archetype:

  $ mvn archetype:generate
...
45: internal -> gmaven-archetype-basic (Groovy basic archetype)
...
Which is located in the Codehaus repository at: http://repository.codehaus.org.

Next, I edited the POM to include dom4j, the final version:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>prystasj</groupId>
<artifactId>schema-validation</artifactId>
<name>Schema Validation</name>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0-rc-5</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy.maven.runtime</groupId>
<artifactId>gmaven-runtime-1.6</artifactId>
<version>1.0-rc-5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
</project>

I wrote up this little script, src/main/groovy/Validator.groovy:
import org.dom4j.io.SAXReader

def (schema, document) = args
def schemaStream = new File(schema).newInputStream()
def documentReader = new File(document).newReader()
SAXReader reader = new SAXReader()
setupSaxReader(reader, schemaStream)
reader.read(documentReader)
println "Document valid.\n"

def setupSaxReader(reader, stream) {
reader.setValidation(true)
reader.setFeature("http://apache.org/xml/features/validation/schema", true)
reader.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true)
reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema")
reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", stream)
}

As you can see, the script takes two arguments, the first being a schema to validate against, and the second is a XML instance docuemnt. I found a test schema from another test project and copied it over to my project directory along with a instance document.

I can run the script by first compiling:

  $ mvn compile
And then using the exec plugin in offline mode (-o) to speed things up as I already have all the jars I need so there's no need for Maven to check:
  $ mvn -o exec:java -Dexec.mainClass=Validator -Dexec.args="order.xsd order.xml"
If the validation succeeds, I'm given the normal BUILD SUCCESSFUL output. If not, the error is presented on the screen, for example:
  Error on line 7 of document  : cvc-complex-type.2.4.b: The content of element 'customer' is not complete.
One of '{country}' is expected. Nested exception: cvc-complex-type.2.4.b:
The content of element 'customer' is not complete.
One of '{country}' is expected.
To finish up, remembering the mvn command is a little rough for me, so I wrapped it into a shell script:
  #!/bin/bash
mvn -o exec:java -Dexec.mainClass=Validator -Dexec.args="$1 $2"
Which I can call with:
  $ ./validate.sh order.xsd order.xml

This little project has proved pretty useful as I can edit the schema or XML instance and run it though rather quickly. I'm sure there are plenty of other methods out there.