Injecting Logs into Seam Beans

Posted by Andy Gavin on Wed, 2009-02-18 15:55

When using the Seam container there is a useful @Logging annotation which injects a Log object at runtime into the bean. In the seam documentation for unit testing the advice generally is to have setters on the class to allow the dependencies to be set. For logging this is not really desirable. One alternative for this is to write a small class that will inject a Log object prior to testing:

import java.lang.reflect.Field;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.log.Log;
 
public class LoggerInjector {
 
	public void injectLogger(Object target,Log mockLog) 
	{
		for ( Field field: target.getClass().getDeclaredFields()) {
			if (field.getAnnotation(Logger.class)!=null) {
				field.setAccessible(true);
				try {
					field.set(target,mockLog);
				} catch (IllegalArgumentException e) {
					throw new AssertionError("Failed injecting logger for test: illegal argument: " + e.getMessage());
				} catch (IllegalAccessException e) {
					throw new AssertionError("Failed to access field to inject logger: " + e.getMessage());
				}
			}
		}
	}
 
}

The seam Log object is a useful at runtime as it removes some of the need to wrap each debug statement in a condition to prevent unnecessary string-concatenation. However to do this java5's varargs are used. This can make setting mocking expectations in frameworks like JMock a little more tricky (not impossible). I tend to produce a dummy object implementing org.jboss.seam.log.Log that outputs nothing and inject that. So a hypothetical test would be:

public class BeanTest 
{
   private SeamBean forTest;
  @Before
   public void setUp()
   {
       LoggerInjector injector = new LoggerInjector();
       this.forTest = new SeamBean();
       //DummyLog is my implementation of Log
       Log dummyLog = new DummyLog();
       injector.injectLog(forTest,dummyLog);
   }
 
   @Test
    public void testSomething()
    {
        ...
    }
 
   ...
}

A drawback of this approach is, if the the @Logger annotation is in a superclass the injection mechanism will not work.

Add new comment