EJB3unit testing: example

Submitted by Jochus on Tue, 02/02/2010 - 18:07 | Posted in: Java



Last week, we tested a framework that could help us testing our service layer (which is created in EJB 3.0). On a previous project, Kim and I tried setting up a JBoss embedded container to perform some unit testing. But it took too much time to set everything up. It also took a while to run the tests with Maven.
So finally, as EJB's 3.0 are just POJO's, we've created them in our TestNG tests with MyEJB myEJB = new MyEJBImpl();. In order to test them correctly, we had to mock some other services/DAO's. Therefore, we used EasyMock. Now, the problem is you need getters/setters to set these mocks on your EJB (which I think is a very bad practice). You could write a "reflection-util-class" which sets the mock in the EJB using reflection, but then again, you're wasting too much time to test something nice.

EJB3unit

The Ejb3Unit project automates Entity and Session bean testing outside the container for the EJB 3.0 specification.

What are the features of EJB3unit?

  • Ejb3Unit is a JUnit extention and can execute automated standalone junit tests for all EJB 3.0 conform JEE projects.
  • The out of container test approach leads to short build-test-cycles, because no container deployment is necessary anymore.
  • EJb3Unit uses an internal in memory database by default. Alternatively a user defined database can be specified. An example configuration can be found here.
  • Ejb3unit is released under the LGPL License.

Personal advantages of EJB3unit

  • Very fast and lightweight
  • Easy to integrate with M2
  • Easy mocking (no need for getters/setters)

Personal disadvantages of EJB3unit

  • The last release dates from: 2008-05-17 (and the package is a RC!)
  • We had to upgrade to the 2.0.0-SNAPSHOT version as we were having some issues with the 2.0.0-RC-1 version
  • The project seems to be dead ... there's not much activity by the developers
  • <a href="mailto:jochen@baileys">jochen@baileys</a> /tmp/ejb3unit $ svn info
    Path: .
    URL: <a href="https://ejb3unit.svn.sourceforge.net/svnroot/ejb3unit
    Repository">https://ejb3unit.svn.sourceforge.net/svnroot/ejb3unit
    Repository</a> Root: <a href="https://ejb3unit.svn.sourceforge.net/svnroot/ejb3unit
    Repository">https://ejb3unit.svn.sourceforge.net/svnroot/ejb3unit
    Repository</a> UUID: 240b23ad-3c12-0410-ab44-d75537e93366
    Revision: 308
    Node Kind: directory
    Schedule: normal
    Last Changed Author: bendt
    Last Changed Rev: 308
    Last Changed Date: 2010-01-10 15:03:25 +0100 (Sun, 10 Jan 2010)

Example

I want to show an example of how it works. The example is a simple service which reverse the name of a user and add his date of birth (I know it's silly, it's just to show how it works).

So my interfaces:

package be.jochusonline.ejb3unitexample;
 
import javax.ejb.Local;
 
@Local
public interface StringManipulator {
	String reverseNameAndAddDob(String s);
}

package be.jochusonline.ejb3unitexample;
 
import java.util.Date;
import javax.ejb.Local;
 
@Local
public interface DateManipulator {
	Date getDateOfBirth(String name);
}

My implementation classes:

package be.jochusonline.ejb3unitexample.impl;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
import javax.ejb.EJB;
import javax.ejb.Stateless;
 
import be.jochusonline.ejb3unitexample.DateManipulator;
import be.jochusonline.ejb3unitexample.StringManipulator;
 
@Stateless
public class StringManipulatorBean implements StringManipulator {
	@EJB
	private DateManipulator dateManipulator;
 
	private static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
 
	public String reverseNameAndAddDob(String s) {
		/* reverse String */
		Integer len = s.length();
		StringBuffer target = new StringBuffer(len);
		for (Integer i = (len - 1); i >= 0; i--) {
		    target.append(s.charAt(i));
		}
 
		/* get DBO */
		Date dob = dateManipulator.getDateOfBirth(s);
 
		return target.toString() + " " + formatter.format(dob) ;
	}
 
}

package be.jochusonline.ejb3unitexample.impl;
 
import java.util.Date;
 
import javax.ejb.Stateless;
 
import be.jochusonline.ejb3unitexample.DateManipulator;
 
@Stateless
public class DateManipulatorBean implements DateManipulator {
 
	public Date getDateOfBirth(String name) {
		// TODO: add implementation ... not needed for example as we are gonna mock this class
		return null;
	}
}

My test class is looking like this:

package be.jochusonline.ejb3unitexample;
 
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
 
import java.util.Calendar;
 
import org.jmock.Expectations;
 
import be.jochusonline.ejb3unitexample.impl.StringManipulatorBean;
 
import com.bm.testsuite.mocked.MockedSessionBeanFixture;
 
public class StringManipulatorTest extends
		MockedSessionBeanFixture<StringManipulatorBean> {
 
	public StringManipulatorTest() {
		super(StringManipulatorBean.class);
	}
 
	public void testReverseStringAndAddDob() {
		/* init mock data */
		final String name = "JOCHEN";
		final Calendar cal = Calendar.getInstance();
		cal.set(1985, 02, 18); // Calendar starts counting months from "0" => 0 = January, 1 = February, ...
 
		/* define mocks/expectations */
		final DateManipulator dateManipulatorMock = this.getMock(DateManipulator.class);
                context.checking(new Expectations() {{
                    one(dateManipulatorMock).getDateOfBirth(name);
                    will(returnValue(cal.getTime()));
                }});
 
                /* run tests */
                StringManipulator stringManipulator = this.getBeanToTest();
                String result = stringManipulator.reverseNameAndAddDob(name);
 
                /* check result */
                final String expectedResult = "NEHCOJ 1985-03-18";
                assertThat(result, equalTo(expectedResult));
 
	}
}

Things to remember:

  • Extend your class from MockedSessionBeanFixture to be able to run the EJB3unit tests (in the background a JUnit process will start). I've used the MockedSessionBean as I want mocking
  • Mock the DateManipulator and create expectations so you're test will return easily

The result in Eclipse:

Comments

Submitted by Uma Lade (not verified) on Thu, 06/05/2010 - 17:47
 

I've a similar case, a service bean with a member of daoBean annotated with @EJB.

I've written EJB3unit test for the serviceBean, and mocked the daoBean. but the mock object (dateManipulatorMock in your example) not getting injected to the main class (StringManipulator in your example).

The getMock() returns a proxy object, but its not being set to the main class, so its always null, so Im getting nullpointerexception when I call the actual method.

Could you please tell me if Im missing anything.

Thanks & Regards
Uma

Submitted by Jochus on Thu, 06/05/2010 - 20:33
 

Uma,

Send me your e-mail through the contact form. I'll send you a message ...

Jochen

Submitted by Jochus on Wed, 22/09/2010 - 17:31
 

You should have enough with the source code?

Add new comment

The content of this field is kept private and will not be shown publicly.

Full HTML

  • Lines and paragraphs break automatically.
  • You can caption images (data-caption="Text"), but also videos, blockquotes, and so on.
  • Web page addresses and email addresses turn into links automatically.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <bash>, <cpp>, <css>, <html5>, <java>, <javascript>, <php>, <sql>, <xml>. The supported tag styles are: <foo>, [foo].
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.