I am trying to find a portable solution to test my Java EE 7 application. It is especially tricky when to test the EJB and their injections. For example:
@org.junit.Test
public void testIsValidCredentials() throws Exception {
System.out.println("isValidCredentials");
String username = "";
String password = "";
Map properties = new HashMap();
properties.put(EJBContainer.MODULES, new File[] {new File("target/classes")});
EJBContainer container = javax.ejb.embeddable.EJBContainer.createEJBContainer();
AuthenticatorLocal instance = (AuthenticatorLocal) container.getContext().lookup("java:global/classes/Authenticator");
boolean expResult = false;
boolean result = instance.isValidCredentials(username, password);
assertEquals(expResult, result);
container.close();
}
When I run test I will get:
No EJBContainer provider available
I also tried to use the option properties.put(EJBContainer.PROVIDER, "")
, but no success. There is some documentation available for Glassfish, but for Wildfly it is really poor.
Also I have heard of arquillian, but I only see Alpha packages, which doesn't seem production safe. Does anyone know a portable solution for (integration) testing?
Here is a fairly standard approach that I use to execute JUnit tests in a Java EE environment.
The basic idea is:
- Write a simple test application with a test Servlet and whatever EJB's you want to test
- Use a JavaSE JUnit test suite to start your app server, and drive GET requests to a test servlet
- Put your actual test logic in a test servlet, this way your test logic will be executing within a Java EE environment
Here is an illustration of what that might look like:
Use a JUnit SE suite with basic test stubs to drive GET requests to your application:
@BeforeClass
public static void oneTimeSetUp() {
// start my app server and make sure apps are installed
}
@AfterClass
public static void oneTimeTearDown() {
// shut down app server
}
@Test
public void testApplicationAvailable() {
runTestInServlet("testApplicationAvailable");
}
@Test
public void testThatFails() {
runTestInServlet("testThatFails");
}
private void runTestInServlet(String testName) {
// Construct the URL, note that the name of the test is passed in
// as the value of the "test" parameter. This will get read from
// the servlet's doGet method
URL url = new URL("http://localhost:9080/myAppName/testServletName?test=" + test);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
try{
con.setRequestMethod("GET");
InputStream is = con.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
// use the BufferedReader to validate response from test servlet
// i.e. search for some "successful test" token
} finally {
con.disconnect();
}
}
Use corresponding methods in a test servlet to execute the real test in a Java EE environment:
@WebServlet(name = "TestServlet", urlPatterns = { "/testServletName" })
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String test = request.getParameter("test");
PrintWriter out = response.getWriter();
try {
System.out.println("-----> " + test + " starting");
// Use reflection to branch out and invoke the method found in the GET method's "test" parameter
getClass().getMethod(test, PrintWriter.class).invoke(this, response.getWriter());
System.out.println("<----- " + test + " successful");
} catch (Throwable x) {
System.out.println("<----- " + test + " failed:");
} finally {
out.flush();
out.close();
}
}
public void testApplicationAvailable(PrintWriter pw) throws Exception {
System.out.prinln("Application and test servlet available");
}
public void testThatFails(PrintWriter pw) throws Exception {
throw new Exception("This test will fail");
}
}
There are third party libs you can use to make this a little more simple, but this is the basic idea. The examples I showed here can all be done with standard Java libraries (and a Java EE environment, of course). The only stuff in here that is specific to what app server you are running on is the server start and stop logic.
Also, I've heard good things about Arquillian, but last I heard it's only supported for a select few Java EE app servers, which would break your portability requirement.