I'm new to writing unit tests for aspects. After some reading on unit testing aspect, I arrived at the conclusion that there two types of tests to write: testing the logic of the aspect, and testing the interception (i.e., is it intercepting correctly). I have a unit test for the logic part. However, I've been struggling with coming up with a test for the interception part.
I'm writing my tests using JUnit 4, JMockit, and Guice (for CDI and AOP).
The class below is my aspect, which logs the execution time of a method call.
class ExecutionTime implements MethodInterceptor {
private static final Logger logger = ...
public Object invoke(MethodInvocation invocation) throws Throwable {
final long start = System.nanoTime();
try {
return invocation.proceed();
} finally {
final long end = System.nanoTime();
logger.trace(...);
}
}
}
In Guice, I created a Module
that is used to initialize an injector. The code is as follows. The binding says that any class and method that is not annotated with @DoNotProfile
is to be ignored by the ExecutionTime
aspect.
class ProfilingModule extends AbstractModule {
public void configure() {
bindInterceptor(not(annotatedWith(DoNotProfile.class)),
not(annotatedWith(DoNotProfile.class)), new ExecutionTime());
}
}
Next, I defined a test class where I can test whether the methods are intercepted correctly. Some of the methods are annotated with @DoNotProfile
.
class TestClass {
public void methodA() {}
@DoNotProfile public void methodB() {}
...
}
Finally, in my test class, I have the following code in my test method.
@Test
public void test() throws Throwable {
Injector injector = Guice.createInjector(new ProfilingModule());
... // not sure what to do next
}
I'm unsure of what to do next. I have tried the following.
invoke
method of the ExecutionTime
class. However, I was unable to get that working.ExecutionTime
and a test module to go with it. That is, .createInjector(new TestModule())
. But I realized that this defeated the purpose of this test, which is to test that the wiring works correctly.I appreciate any insights and help on this matter.
If you run in these kind of problems, take a step back and think again: what are the building blocks of my application? Then tests these as arbitrary units.
In your case: "Does the MethodInterceptor call the logger with the right values" and "Does the module correctly bind the ExecutionListener". I assume that you already have the first one done.
For the second one: Override the module in your unit test to provide a mock for the ExecutionListener, then just verify its "invoke" method gets called/not called depending on the presence of the annotation.
Since MethodInterceptors can only be bound as concrete instances, the simplest approach would be to provide a constructor for the module that passes the ExecutionListener instance. Then you could use a new instance as default and pass a mock in test.