Testing in Jboss Seam: how to, and some common problems

Introduction

In this article I explain how to bootstrap the Jboss embedded server and I share some common problems with running Seam integration tests with the Jboss embedded server.
It is not meant as a readthrough, but meant for people having trouble getting their SeamTest to run.

Audience

This article is meant for Java developers who are building applications with Seam.
This article also assumes the reader is familiar with the TestNG test framework.

Setting up Jboss embedded

Unit testing with Seam is easy. Since all your components are POJOs, they can easily be tested in isolation with regular TestNG annotated classes. But if you want integration tests(obviously you cant do this outside of the container), you need to get the Jboss embedded server up and running(well, you can also deploy to a real application server for the tests, but initiating a test is going to take considerably longer then).

For the purpose of this tutorial, please download the Jboss embedded server. Open the downloaded zip file. The two directories we will need are the bootstrap folder and the lib folder.

You will need the contents of both of these on your classpath in order to run Jboss Embedded.

Note: I actually never downloaded the Jboss embedded server myself. When you use seam-gen, the generated project contains the necessary libs and the bootstrap folder already.
I am going to assume that you know how to add the jars in the lib folder to your project. When you are using Maven, you can define the dependencies in your pom:
<dependency>
	<groupId>org.jboss.seam.embedded</groupId>
	<artifactId>hibernate-all</artifactId>
	<version>beta3.SP9</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.jboss.seam.embedded</groupId>
	<artifactId>jboss-embedded-all</artifactId>
	<version>beta3.SP9</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>org.jboss.seam.embedded</groupId>
	<artifactId>thirdparty-all</artifactId>
	<version>beta3.SP9</version>
	<scope>test</scope>
</dependency>

You should copy the bootstrap folder into your project and make sure it is on the classpath as well. If you get a “conf/bootstrap-beans.xml” DeploymentException, it means it isnt.

Right now, the Jboss embedded is ready to run. Run the following testNG test to test it.

public class RunEmbeddedJbossTest {
	@Test
	public void testBootstrapEmbeddedJboss(){
		try {
			Bootstrap bootstrap = Bootstrap.getInstance();
			bootstrap.bootstrap();
		} catch (Exception e) {
			assert false: "Failed to start Jboss Embedded.";
			e.printStackTrace();
		}
	}
}
Note: If you are using Eclipse, you can run TestNG tests from you IDE with the TestNG eclipse plugin. Once installed, you can run them from the popup menu: Run as>TestNG test.
Or you can try to run the following empty SeamTest:
public class RunSeamTestTest extends SeamTest{
	@Test
	public void testRunSeamTest() throws Exception {
		new ComponentTest() {			
			@Override
			protected void testComponents() throws Exception {
			}
		}.run();
	}
}

SeamTest is a test class that comes with Seam with a lot of infrastructure code for constructing mocks, and will bootstrap the Jboss Embedded container automatically when required(as in the above test).

Common problems

If the above test is failing, and the necessary libs and bootstrap folder are on the classpath, it is probably because of one of the following reasons.
Note that at some point these errors will probably be fixed. Maybe they are already fixed at the time of this writing.

1. When using Java 1.6, you need to pass -Dsun.lang.ClassLoader.allowArraySyntax=true as a VM argument

In Java 1.5, you could run something like:

public class LoadClassTester {
      public static void main(String[] args) throws Exception {
          String[] s = new String[] { "integrating stuff" };
          String className = s.getClass().getName();
          LoadClassTester.class.getClassLoader().loadClass(className);
      }
}

This however was not supposed to work. The array className, e.g. “[Whatever”, was never meant to be a valid argument for the ClassLoader.loadClass method.
Class.forName(className, false, classLoader) should be used instead in the above case.
The idea was to disallow this array syntax in 1.5 but for some reason this was deferred to 1.6.
Unfortunately, some libs, like the jboss embedded jars, are still passing the array className to the above loadClass method, which results in tons of ClassNotFoundExceptions.

So, you will need to add

-Dsun.lang.ClassLoader.allowArraySyntax=true

as a vm argument when running your test.

2. No spaces are allowed in path to bootstrap

Lately, I’ve been developing on Ubuntu a lot. And when developing on Windows, my workspace is probably located at something like c:\development\workspace. But last week, I had to work a bit on a Windows machine where my workspace was under c:\Document and Settings\username\workspace – the default workspace location on Windows machines.
Suddenly, all my SeamTests started failing. My Jboss Embedded server couldnt boot. The list of errors was even weirder than the list of [java.lang.String ClassNotFoundExceptions from the previous section. All because I had spaces in my path to the bootstrap.

3. Resolving classpath problems

By now, at least the first test – testBootstrapEmbeddedJboss – should run without problems. If it is, but the SeamTest is still not running properly, you are properly getting NoSuchMethodErrors or ClassNotFoundExceptions. This means one of the Jboss Embedded server libs contains jars that conflict with other jars that are in your project.
For example, when you import the latest version of hibernate-entitymanager(3.4) and the latest version of jboss-embedded(beta3.sp9) with maven there will be conflicting javassist.jars on your classpath. The solution is to exclude javassist as an imported dependency from hibernate-entitymanager.