Two minute tutorial
This guide assumes you are familiar with the basics of EJBs and unit-testing with JUnit. Skim it to get the basic idea - the really interesting bits of code are in bold to make it even easier to skim.
The classes we want to test
We are going to call a method on a stateless session bean, called GreetingService which will say "hello". The GreetingService is made up of a home and remote interface and an implementing class, that look like this:
public interface GreetingServiceHome extends EJBHome {
GreetingService create() throws RemoteException, CreateException;
}
public interface GreetingService extends EJBObject {
String greet() throws RemoteException;
}
public class GreetingServiceBean implements SessionBean {
public String greet() {
return "hello";
}
// session bean lifecycle methods omitted...
}
Note: Package names have been removed for brevity.
The unit test
We want our test to do the following:
- Get a JNDI context.
- Look up the home interface.
- Cast it to a GreetingServiceHome using the standard RMI object narrowing mechanism.
- Get a remote stub.
- Call a method on the remote stub.
- Return it to the pool.
- Make sure it all worked.
Wrapped up in a JUnit test case, the code looks like this:
public class GreetingServiceTest extends TestCase {
public void testShouldSayHello() throws Exception {
// execute
Context context = new InitialContext(); // 1
Object obj = context.lookup("ejb/greetingService"); // 2
GreetingServiceHome home =
(GreetingServiceHome)PortableRemoteObject.narrow( // 3
obj, GreetingServiceHome.class);
GreetingService service = home.create(); // 4
String result = service.greet(); // 5
service.remove(); // 6
// verify
assertEquals("hello", result); // 7
}
}
If we just run this test as is, it will fail. Probably with an error with the default naming context (com.sun.enterprise.something blaming org.omg.CORBA.something for not finding a bunch of config files).
Getting it working - the easy way
Assuming you have an ejb-jar.xml, you can get XJB to do all the legwork by simply passing it a java.io.Reader:
public void setUp() throws Exception {
new XjbEjbJarParser().read(new FileReader("/path/to/ejb-jar.xml"));
}
And that's it! The test passes and we are in business.
The ejb-jar.xml processing is pretty comprehensive, so you get all your <ejb-link>, <env-ref> and <resource-ref> setup for free. What's more, you can read multiple ejb-jar.xml files, and circular references will be resolved properly.
Getting it working - the programmatic way
If you don't have an ejb-jar.xml or you want a more fine-grained setup, you can configure XJB programmatically. So what is the simplest way we can get this test to pass? We need to associate the home and remote interfaces with a bean instance, give it a name and put it in the JNDI tree. To do all this, we use an EjbConfigurator like so:
public void setUp() throws Exception {
EJBHome home = new XjbEjbConfigurator().registerSessionBean(
"greetingService",
GreetingServiceHome.class,
GreetingService.class,
new GreetingServiceBean()
EjbConfigurator.STATELESS);
}
This single method call creates a fully-functional implementation of GreetingServiceHome, with all the associated plumbing and metadata. It also installs XJB as the default JNDI implementation, and registers the EJB under several common names, including "ejb/greetingService", so there is nothing more to do, and we can test our EJB outside of the container.
Summary
To recap:
- XJB takes up as few lines as it possiby can in your test setup.
- The configurator can read your ejb-jar.xml file(s) and "deploy" your EJBs. This is very fast.
Where next?
If you want to stub out JDBC or do end-to-end integration testing with XJB (guess what? it's easy) you should take a look at configuring JDBC DataSources, and maybe read about how you can use Null Objects to make testing easier.