devxlogo

Unit Test Secured EJBs in Production

Unit Test Secured EJBs in Production

nit testing, a critical part of the software development process, involves individually testing each unit of code to make sure that it works correctly on its own. Performed at different layers of an application, unit tests run best when they are done quickly and kept in mutual isolation.

If the application under test is EJB-driven (that is, if its business logic is encapsulated in EJBs), it makes sense to test the EJB as well. However, unit testing EJBs is a complex job, which becomes even more difficult when the EJBs are secured through method-level, role-based permissions.

A test case typically constructs the object it is testing, but the object being tested is sometimes dependant on the behavior of other objects. In that case, the test case stubs out the needed behavior as a “mocked behavior”. This works fine when testing a standalone component, but testing code that runs in an application server, such as EJB, becomes complicated.

EJBs are not supposed to be constructed directly by the callers. They usually require the context provided by the server to properly construct itself. Without that, they don’t function correctly. To properly test EJB, you must build the application, deploy the EJB to the application server, and then execute the JUnit tests against the remote interfaces of the EJBs. This removes a lot of the automation from the testing, and (as we all know) the harder it is to test, the less testing will get done. And again, it becomes more complex when the EJB is secured through method-level permissions, which are related to roles.

Introducing the JUnitEE Unit-Testing Framework

Among the very few unit-testing frameworks that deal with this kind of scenario, Apache Cactus is a prominent one. It extends the JUnit framework to handle unit testing for server-side Java components such as EJBs, servlets, JSPs, etc., and provides an authentication mechanism through its support of the BASIC and FORM authentication methods. This facilitates unit testing of servlet codes that use the Servlet Security API.

A lesser-known unit-testing framework, JUnitEE, is also suitable for running in an application server environment. Although not as versatile as Cactus, JUnitEE is easier to use. It does not provide an authentication mechanism, but you can easily create an API on top of JUnitEE that will handle the authentication process and run test cases in a secured environment.

This article shows how to unit test secured EJBs deployed in the IBM WebSphere Application Server using the JUnitEE framework. Even though it uses IBM WebSphere for demonstration, you can apply its concepts to unit test secured EJBs that are deployed in other application servers as well.

Run JUnitEE-Based Test Cases

To access and invoke methods on a secured EJB, you should first authenticate the remote call to the secured EJB. It then should have the proper role. In the case of IBM WebSphere Application Server, the test should be in the context of the container (i.e., the test effectively is in-container).

The following is the code for your JUnit test case in IBM WebSphere Application Server:

		protected void setUp() throws Exception {	super.setUp(); 	Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.ibm.websphere.naming.WsnInitialContextFactory"); env.put(Context.PROVIDER_URL,"iiop://localhost:4084/"); try { initialContext = new InitialContext(env); } catch (NamingException e) { e.printStackTrace(); }} protected void tearDown() throws Exception { super.tearDown(); try { initialContext.close(); } catch (NamingException e) { e.printStackTrace(); } initialContext = null;} public void test1 () throws Exception { TestFacadeHome home =
(TestFacadeHome)javax.rmi.PortableRemoteObject.narrow(initialContext.lookup("TestFacadeHome"),TestFacadeHome.class); TestFacade tFacade = home.create(); result = tFacade.someMethod(); // Do your testing here. assertNotNull(result);}

The remainder of the article shows you how to:

  1. Create a custom servlet based on the JUnitEE servlet, JUnitEEServlet
  2. Set up the environment for unit testing secured EJBs
  3. Run the unit tests

Once you’ve completed these steps, your sample code will read the environment settings of the IBM WebSphere Application Server, perform programmatic login into the application server, and then run the test cases in the authenticated context of the application server.

Create a Custom Servlet

Begin by creating the custom servlet code:

  1. Override the init method of the JUnitEEServlet servlet with the following code:
    		public void init(ServletConfig config) throws ServletException {            super.init(config);   	Hashtable env = new Hashtable();   	env.put(Context.INITIAL_CONTEXT_FACTORY,   	 "com.ibm.websphere.naming.WsnInitialContextFactory");   	env.put(Context.PROVIDER_URL, config.getInitParameter("PROVIDER_URL"));  Context initialContext = null;   	try {  	initialContext = new InitialContext(env);  	Object obj = initialContext.lookup("");  } catch (NamingException e) {	  	e.printStackTrace();  }                //programmatic log-in     	LoginContext lc = null;   	 try {   	 	lc = new LoginContext("WSLogin",new WSCallbackHandlerImpl(config.getInitParameter("USER_ID"), _
    config.getInitParameter("PASSWORD"))); lc.login();} catch (LoginException le) { System.out.println("Cannot create LoginContext. " + le.getMessage());} catch(SecurityException se) { System.out.println("Cannot create LoginContext." + se.getMessage()); }subject = lc.getSubject();}
  2. Override the runTests method of JUnitEEServlet with the following code:
    		  //running test cases in the WebSphere secure environment.        protected TestRunnerResults runTests(String test, String[] testClassNames, HttpServletRequest _
    request, boolean forkThread) { final String iTest = test; final boolean bForkThread = forkThread; final String[] testNames = testClassNames; final HttpServletRequest fRequest = request; final TestRunnerResults results = new TestRunnerResults(); final TestRunner tester = new TestRunner(this.getDynamicClassLoader(), results, forkThread); try{ WSSubject.doAs(subject, new java.security.PrivilegedAction() { public Object run() { java.security.AccessController.doPrivileged(new java.security.PrivilegedAction() { public Object run() { String id = fRequest.getSession().getId(); System.setProperty("sessionid",id); if (iTest == null) { if (bForkThread) { HttpSession session = fRequest.getSession(true); session.setAttribute(TESTRUNNER_KEY, tester); session.setAttribute(TESTRESULT_KEY, results); } tester.run(testNames); } else { tester.run(testNames[0], iTest); } return null; } }); return null; } }); } catch (Exception e) { e.printStackTrace(); } return results; }
  3. Override the service methods with the following:
    		public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {super.doGet(request, response);      }public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {super.doPost(request,response);}

The Environment for Unit Testing Secured EJBs

The following steps will help you set up and configure the environment for unit testing secured EJBs using IBM’s Rational Application Developer (RAD) or Rational Software Architect (RSA) IDEs. Since the steps are generic in nature, you should be able to apply them for use with Eclipse as well. In any case, you won’t be able to run the JUnitEE-based JUnit test cases without first doing the following:

  1. Create a jar file (say, sample.jar) out of the custom servlet you created.
  2. Create a Web Project (Dynamic Web Project) named SampleWeb.
  3. Put the following jars under the WEB-INF/lib folder of the SampleWeb project: junit.jar, junitee.jar, and sample.jar.
  4. Create a JUnit class under SampleWeb named SampleTest. All JUnit classes need to be here.
  5. Add to the SampleWeb project under WEB-INF a text file that lists the JUnit classes. The JUnitEE servlet reads this file to determine which JUnit classes to load for testing. Name the text file testCase.txt.
  6. Open the testCase.txt file and add the name of the JUnit classes to be tested, such as SampleTest. Save the file.
  7. Edit web.xml so it looks as follows:
    		     "http://java.sun.com/dtd/web-app_2_3.dtd">	SampleWeb					SampleServlet         SampleServlet		 test runner		SampleServlet                             PROVIDER_URL             iiop: //localhost:4084/                             USER_ID             userid                             PASSWORD             password        				SampleServlet		/TestServlet/*				index.html		index.htm		index.jsp		default.html		default.htm		default.jsp	

Initialization parameters (like provider URL, user ID, password, etc.) can also be read from a property file or other resources on the classpath. In fact, you don’t need to pass a provider URL as an initialization parameter to the Context. Since you will deploy the Web application under unit test in the same server (i.e., the WebSphere environment) as the EJBs, if you don’t pass the provider URL, the initial context factory in the application will use the server ORB instance.

Run the Unit Tests

To run the unit tests from your browser, simply point your browser to: http://localhost:4085/SampleWeb/TestServlet. The port should be the one on which the Web Project (in this case, SampleWeb) is deployed. The browser will list all the tests to be run, which are listed in the testCase.txt file. You can select and run one, many, or all the tests.

To run the unit tests from an ant build script, take the following steps:

  1. Put the junitee-anttask.jar from JUnitEE in the WEB-INF/lib folder of the Web Project.
  2. Create a build.xml file similar to the following in the WebContent folder:
    		    		  	    	  			  	    	  	

Testing Secured EJB-based Apps in Production

Of course, you can use the concepts in this article to unit test secured EJBs that are deployed in application servers other than IBM WebSphere. To make programmatic login into the application server, you first need to identify the initial context factory relevant to your particular app server and then put it in the servlet code. Next, you need the proper JAAS login module in the app server in order to create a successful login context. You could also create and use a custom JAAS login module. Lastly, you need to modify your code so it can run the test cases in the authenticated context of your app server.

By unit testing secured EJBs in the way described here, you gain the advantage of testing EJB-based applications in the same runtime production environment without needing to switch off the role-based, method-level permission settings. As a result, you minimize the risk of your tests failing when they run in user acceptance test (UAT) or production environments.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist