Thursday, July 16, 2009

Getting Started with MockEJB

I spent a little time recently trying to get a lightweight framework for some basic EJB unit testing with the goal in mind to reduce the number of times that I had to deploy to the application server to test new code.  I had been using MockRunner for a while to test tag classes, so I thought I would try to use the EJB component which uses MockEJB as a base for testing.

The hardest part of the whole thing was really figuring out how to get the finders to work, but as usual, I was likely making it a bit harder than I had to, this is how I did it.


MockRunner provides a base class for doing an EJB Test Case called EJBTestCaseAdapter, the setUp() method does pretty much everything to do with setting up your context and creating the basic environment, all you have to do is deploy your EJB classes.  The base class has methods for deploying both entity and session interfaces, but I found that the deploy(BasicEjbDescriptor) method worked best for me, giving me the flexibility to deploy local and remote interfaces from multiple packages.  The deploySession and deployEntity methods the the MockRunner class just provide a wrapper for the deploy method to reduce some of the complexity.  So as long as you don’t have a complicated project, they should work fine for you.

I extended this test case adapter class to make my life a little easier and implemented my own deploy methods since my entity and session classes are in different packages.  This just makes life a little easier because now I just have to use deployMyEntity(“Tblwhatever”):

  1: protected void deployMyEntity(String name) throws Exception
  2: {
  3:     final String interfaceName = "my.entity.package." + name;
  4:     ejbModule.deploy( new EntityBeanDescriptor(
  5:         "java:comp/env/ejb/local/" + name,
  6:         Class.forName(interfaceName + "LocalHome"),
  7:         Class.forName(interfaceName + "Local"),
  8:         Class.forName(interfaceName + "Bean")));
  9: }

Sessions are a little bit more complicated because our naming convention for Remote and Local Interfaces are a bit different:

  1: protected void deployMySession(String name, boolean local) throws Exception
  2: {
  3:     final String myPackage = "my.session.package.";
  4:     final String interfaceName = myPackage + name;
  5:     final String jndiName = name;
  7:     if ( local )
  8:     {
  9:         jndiName = "java:comp/env/ejb/local/" + name;
 10:         interfaceName = interfaceName + "Local";
 11:     }
 13:     ejbModule.deploy( new SessionBeanDescriptor(
 14:         jndiName,
 15:         Class.forName(interfaceName + "Home"),
 16:         Class.forName(interfaceName),
 17:         Class.forName(myPackage + name + "Bean")), TransactionPolicy.REQUIRED);
 18: }

Both of these classes make reference to an ejbModule which are provided by a method in the EJBTestCase Adapter.  I set this up in my setUp() method:

  1: protected final EJBTestModule ejbModule;
  2: protected final JDBCTestModule jdbcModule;
  4: @Override
  5: public void setUp() throws Exception
  6: {
  7:     super.setUp();
  9:     jdbcModule = createJDBCTestModule();
 10:     ejbModule = createEJBTestModule();
 11:     ejbModule.bindToContext("jdbc/MyDS", 
 12:         getJDBCMockObjectFactory().getMockDataSource());
 13: }

Creating a Test

My TestCase simply extends this class where I deploy the sessions and entities that I will need during my test.  For simplicity, I have a simple entity that has an id field that I want to update

  1: public class MyTest extends MyEJBTestCaseAdapter
  2: {
  3:   @Override
  4:   public void setUp() throws Exception
  5:   {
  6:     super.setUp();
  8:     deployMySession("MySessionEJB", false);
  9:     deployMyEntity("Tblsomething");
 10:   }
 12:   public void testSomething() throws Exception
 13:   {
 14:     final MySessionEJB session = EjbHomeFactory.lookup("MySessionEJB");
 15:     session.updateSomething(1L);
 17:     final Tblsomething t = findByPrimaryKey(1L);
 18:     assertEquals(1L, t.getId());
 19:   }
 20: }

Dealing with Aspects

Assuming that your session just creates the Tblsomething entity, you likely will not have a problem running this test.  But if you are looking up an entity, you will have to implement an Aspect that will intercept your finder and return something for you to play with.  Here is a simple Aspect that intercepts a findByPrimaryKey method and returns a new entity that is probably suitable for a simple test:

  1: class FinderHandler implements Aspect
  2: {
  3:     FinderHandler(String entity, String finderMethod, Object[] createParams, Object pk)
  4:     {
  5: 	targetEntity = entity;
  6: 	targetFinder = finderMethod;
  7: 	entityToReturn = 
  8:           createEntityBean("java:comp/env/ejb/local/" + entity, 
  9:              createParams, pk);
 10:     }
 12:     private final String targetEntity;
 13:     private final String targetFinder;
 14:     private final Object entityToReturn;
 16:     public Pointcut getPointcut()
 17:     {
 18: 	return new MethodPatternPointcut(
 19:                targetEntity + ".*" + targetFinder);
 20:     }
 22:     public void intercept(InvocationContext invocationContext)
 23:     {
 24: 	invocationContext.setReturnObject(entityToReturn);
 25:     }
 26: }

This aspect class will basically create an entity that you define using the parameters of your create method as an Object[].  The EJBTestCaseAdapter class provides this handy utility for creating an entity by looking up the class and using Reflection to find the create method and invoking it and then persisting the entity in an in memory data source that can then be retrieved using the findByPrimaryKey(Object) method in your test case.


Obviously, this kind of test does nothing to attempt to test the actual EJB platform with all of its intricate dependencies and configurations, but it does allow a developer to execute EJB code on their development workstations and apply TDD principles when developing EJB code.

Thursday, July 9, 2009

Creating Testable Web UI Components

Until recently, I always thought that the only way to test the UI components in an application was to create an end-to-end test using some kind of robot user.  The reason being is that much of the UI is created using JSP pages or custom tags…these are sometimes hard to run separately outside the application, so we’ve created tests for them before but running front end tests and hoping for good results.

Since this is painful to do any detailed testing on, we generally resort to good old human testing in our QA department to make sure that the UI comes out right…obviously a bad practice.

This article goes through a case study on how to create a testable UI component using a custom tag and shows the various tests I use to validate the code.

The Tag Class

If you look at some of my old code for tag classes, you end up with some very complicated presentation logic to try and follow.  My thought on this at the time was to put the complicated logic in a tag class instead of using struts logic tags and scriptlets in my JSP page.  Although using a tag class is preferred to this, I now view my tag class as simply being the ‘glue’ between the data that I am trying to present and how it is presented.

What I mean by this is that, the tag class should really be used for getting a reference to the data that you want to display and passing it to the components which render the output and then passing that output to the browser.  The actual tag reference is just a place holder to get that output in the right spot on the page.  This model makes for cleaner, easily testable code.  When you want to test the functionality of a tag class, you simply need to write a test that validates that when you pass a reference to the tag, it can find the data it needs and render an output, you don’t have to try and test all of the possible output issues involved.

The Renderer

Our application uses Struts, so a renderer is not technically part of the framework at this point as it is in say JSF.  The concept is that of a component that can convert a data structure into some form of visual representation, as in say HTML.  I use the term ‘renderer’ to refer to any software component that does this type of translation.

I usually start with a renderer interface since it is likely that I may need to render this component in one of many ways.   I pass off the responsibility of selecting the appropriate renderer to the tag class this way I can make configurable outputs.  The renderer is specific enough to be able to perform simple presentation logic, this makes the testing of a renderer component fairly straight forward.

Consider this interface:

  1: public interface ClientRenderer
  2: {
  3:     String output(Client client);
  4: }

I love using interfaces in this case because I don’t have to worry about what my output will look like to get it all wired together.  I can make a very simple implementation that will just output the clients name for starters

  1: public class SimpleClientRenderer
  2: 	implements ClientRenderer
  3: {
  4: 	public String output(Client client)
  5: 	{
  6: 		return client.getOrganizationName();
  7: 	}
  8: }

A test for this class is very simple to do and doesn’t require that you use a whole bunch of mock framework classes:

  1: public class SimpleClientRendererTest
  2: 	extends TestCase
  3: {
  4: 	public void testOutput() throws Exception
  5: 	{
  6: 		final Client cl = new Client();
  7: 		cl.setOraganizationName("testme");
  9: 		final ClientRenderer r = new SimpleClientRenderer();
 10: 		final String out = r.output(cl);
 12: 		assertEquals("Unexpected Output", "testme", out);
 13: 	}
 14: }

Obviously, this is a very simple example that would likely be handled with a bean:write tag, but the idea is that this renderer class doesn’t have any framework dependencies to test.  It is simply a class that outputs in a predictable (and therefore testable) manner.

Testing the Tag Class

JSP Tag classes run within a framework and require references to a pageContext, a request and a response.  I use MockRunner for testing tag classes since they can run within the context of my build server and don’t have to be deployed anywhere.

Since I’ve already tested the fact that my client will render the correct way, all I need to test now is that I can get the correct reference to my renderer.

  1: public class ClientOutputTag
  2: 	extends TagSupport
  3: {
  4: 	private Client clientRef;
  5: 	protected String attribute;
  7: 	public void doStartTag() throws JspException
  8: 	{
  9: 		... // get client ref from whereever
 10: 	}
 12: 	public void doEndTag() throws JspException
 13: 	{
 14: 		final ClientRenderer r = new SimpleClientRenderer();
 15: 		final String out = r.output(clientRef);
 17: 		try
 18: 		{
 19: 			pageContext.getOut().write(out);
 20: 		}
 21: 		catch(IOException e)
 22: 		{
 23: 			// error
 24: 		}
 25: 	}
 27: 	... // req'd accessors
 28: }

As you can see by this implementation, the tag class is responsible only for getting the reference and calling the renderer, you test would look something like:

  1: public class ClientOutputTagTest
  2: 	extends BasicTagTestCaseAdapter
  3: {
  4: 	public void testTag() throws Exception
  5: 	{
  6: 		final Client cl = new Client();
  7: 		cl.setOrganization("testme");
  8: 		final ClientOutputTag tag = 
  9: 			(ClientOutputTag) createTag(ClientOutputTag.class);
 11: 		tag.setAttribute("client");
 12: 		setRequestAttribute("client", cl);
 14: 		tag.doStartTag();
 15: 		tag.doEndTag();
 17: 		final String out = getOutput();
 19: 		assertEquals("Unexpected Output", "testme", out);
 20: 	}
 21: }

This is a simple example, so there isn’t much to test here.  I may want to test to make sure that if I’m outputting html, that it will be valid or something like that; I would use a sax parser for that.

Wednesday, July 8, 2009

Why are We Embarrassed to Admit That We Don’t Know How to Write Tests? | Javalobby

I found this excellent article today on writing testable code.  I find one of the big problems in our organization is that we know we need to test code, and it sounds like a simple thing to do, but it is difficult thing to get your head around.

This article talks about making your code testable.  It is important to differentiate between writing unit tests and writing end-to-end tests.  An end to end test is a test that acts like the user for your application, and it is good for finding wiring bugs.  Unit tests on the other hand, handle much simpler form of bug and a more common form of bug.

I recommend this article for all developers were not currently writing unit tests for all of their code.

Why are We Embarrassed to Admit That We Don’t Know How to Write Tests? | Javalobby