Skip to main content

A Simple Servlet for Running JUnit in Glassfish

Posted by cayhorstmann on February 14, 2009 at 8:37 PM PST

When teaching unit testing in the context of a simple EJB3.1 application, I
was looking for an easy way of testing managed beans and session beans inside
Glassfish. Of course, one can test out-of-container or use an embedded
container (but I didn't quite figure out how to do that with Glassfish
v3—I'd appreciate hints), or a href="http://ejb3unit.sourceforge.net/">mock container (but that seemed to
require a bit of setup).

I hit upon a scheme that I had not seen elsewhere: put the unit tests in the
container and trigger them with a servlet that reports the outcomes.
Advantages:

  1. There is very little setup to learn
  2. It is easy to run the tests from a browser
  3. The tests run in the exact same environment as your app
  4. No need to wait for container startup with every test. (This could also
    be a disadvantage because the database isn't in a pristine state at the
    beginning of each test.)

Here is how to do it.

Add the JUnit 4 JAR to WEB-INF/lib.

Add the following servlet to your WAR file:

package myapp.servlets;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.junit.internal.JUnitSystem;
import org.junit.runner.JUnitCore;

public class TestServlet extends HttpServlet {  
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
       String className = request.getParameter("class");
       response.setContentType("text/plain");
       OutputStream out = response.getOutputStream();
       final PrintStream pout = new PrintStream(out);
       new JUnitCore().runMain(new JUnitSystem() {
         public PrintStream out() { return pout; }
         public void exit(int arg0) {}
       }, className);
       out.close();
   }
      
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
   throws ServletException, IOException {
       doGet(request, response);
   }
}

Add the following entries to web.xml:

    <servlet>
        <servlet-name>TestServlet</servlet-name>
        <servlet-class>myapp.servlets.TestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TestServlet</servlet-name>
        <url-pattern>/test</url-pattern>
    </servlet-mapping>

Write your JUnit test case in the usual way. For example, here is a test for
a session bean:

package myapp.session;

import static org.junit.Assert.assertEquals;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.junit.Before;
import org.junit.Test;

import myapp.entity.Person;

public class UserSBTest {
   private UserSB userSB;

   @Before public void init() throws NamingException {
      InitialContext context = new InitialContext();
      userSB = (UserSB) context.lookup("java:global/MyApp/UserSB");
   }
  
   @Test public void testAddUser() {
      Person p = new Person();
      p.setFirstName("Fred");
      p.setUsername("fred");
      userSB.save(p);
      Person q = userSB.find("fred");
      assertEquals(p.getFirstName(), q.getFirstName());
      userSB.removePerson("fred");
   }  
}

Unfortunately, you can't just have the container inject the session bean.

   @EJB private UserSB userSB; // Doesn't work when JUnit loads the class

When JUnit loads the class, it doesn't deal with EJB annotations.

Then point your browser to
http://localhost:8080/MyApp/test?class=myapp.session.UserSBTest

unit-test-in-browser.png

Proverbial exercise to the reader: Add a green bar when the test cases
pass.

Comments

Thanks--I agree that using OpenEJB is a reasonable approach. I understand there is now (or there soon will be) a way of embedding Glassfish in a similar way, but I haven't yet figured out the setup.

Hi, That's actually a nice way of doing it. I've worked on projects where we had a whole maven build that used a small container (OpenEJB) to load our EJB 3.0 components and test them. Setting it up was a pain as you can imagine. Now I'm looking for a way to do something simpler as part of a pet project of mine and this fits the bill nicely. You could even run this during deploy and throw a fat Runtime exception when a test fails and thus bail out of the deploy. Thanks

Thanks for the tip about easygloss. Of course, what I really want is not to have to worry at all but find a way for the container to do the injection. Is there some way to locate the ambient app server, hand it an object, and say "hey, inject this"?

You could also have a look at easygloss.dev.java.net It could certainly handle injecting your injectables for you ;-) It also might be easier, with EasyMock, for running the tests outside of the servlet container

Thanks, but Cactus is much more heavyweight than what I was looking for. Maybe because it has been there for many years :-)

Apache Cactus has been there for years http://jakarta.apache.org/cactus/