This post illustrates a subtle relationship between Mock Objects and Aspect Oriented Programming. Some code examples are shown, and ends with questions for further research. This is a follow on to a prior “Using AspectJ For Testing Legacy Code“. Author: Josef Betancourt
Categories and Subject Descriptors
D.2.2 [Software Engineering]: Design Tools and Techniques, Object-Oriented programming
interceptors, AOP, Mock Objects, JMockit, JUnit, Aspectj, unit test
In Unit testing during code development and maintenance, the smallest unit of code is tested in isolation from collaborating units or subsystems. In well designed systems, testing is much simpler: outgoing interfaces are easier to manage. In legacy systems and/or badly written code, that may not be the case. Further, when testing legacy systems, changes to increase testability are not always possible.
Thus, various patterns, frameworks, and tools are used to support this isolation. Mock Object frameworks are ideal for this. Aspect Oriented Programming (AOP) is also capable of providing this isolation but is rarely mentioned. What are the differences? Is one better than another for testing?
Mock Objects are simulated objects that mimic the behavior of real objects in controlled ways.
The JMockit toolkit is a modern Java mocking toolkit. One distinguishing feature of JMockit is that it is powerful enough to Mock legacy unmockable code.
A Client class uses a Service object’s query method to get a user’s name: Client.getUserName(int) –> Service.query(int).
For the test we want to substitute the name for a specific argument. When invoked with argument integer 1, the result is the string “second”, but in the test we want to return “Hello world!”. This example is just to show the technology; a hello world app, not practical in itself.
To intercept a method call on an object in AOP an Aspect is created.
The Advice below is written in the annotation based AspectJ syntax introduced in AspectJ 5.
This defines a method that will ‘replace’ the original target. The terminology used by the AspectJ programming manual:
AspectJ defines many Join Points. There is even a Handler execution join point: “When an exception handler executes. Handler execution join points are considered to have one argument, the exception being handled”.
The pointcut language is very rich and the signature patterns can be generic or very specific.
We can also use an anonymous pointcut instead:
Note that the advice, here doQuery(..), does not have to match the original target method’s name.
In JMockit‘s State Based API an object can be mocked by using a MockUp class. Within that class any method that needs to be mocked is re-implemented and annotated with @Mock.
Since JMockit allows even private, final, or static methods to be overridden, this is not normal Java method overriding.
We can also define the mock using an anonymous inline class within the test method:
Structure and Syntax
Compare this to the prior Aspect. They are both a class definition. The new behavior is also a method. The difference is the pointcut. In JMockit the pointcut and the advice specification are combined. Note that the method signature must match the target method’s. In the AspectJ Aspect, these are separate.
The combined syntax in the Mock approach is simpler, and since a test is usually targeted at one specific method, the extra AOP pointcut expressiveness may have limited use. The Mock class can even be created in the test inline. A paper referenced below even makes the suggestion that test based pointcut definitions are an improvement to AOP since they are less fragile.
The aspect must be created as a static class and the associated advice is instrumented at compile time. The mock is integrated in the JUnit run time so it’s ‘advice’ is active only for the current test, thus, you have more opportunities for various tests of the same target. The full source code of the test using Aspects does not have as many assertions as the one written using Mocks because of this early instrumentation. See section below for listings.
There are more differences. These are of course due to the intended application of these two technologies. AOP is a more general purpose systems tool. Crosscutting concerns are an architectural artifact whereas isolation is a testing concern.
Mocks are a subset of Aspects
AOP is optimized for cross-cutting concerns. But, collaborator isolation is just an example of a single-use test-based cross-cutting concern. So Mocks are just a special use of general AOP capabilities.Mocks supply a single joinpoint, and in many implementations allow the use of an Around advice. This has been sufficient and with other features such as Expectations, the Mock Objects framework fits well into current testing approaches.
In AOP there is a richer language for selecting different kinds of joinpoints. And the pointcuts are used by different kinds of advice, such as cflow, before, after, around, and so forth. The modularization (inheritance and other features) into Aspects presents an opportunity for more high-level syntax and use, especially with the annotation based language.
Can Mock Objects use AOP techniques?
This begs the question of whether Mock Objects can or should use generic AOP techniques? If so how?
One example of the integration of AspectJ is the Spring framework, which now can use the AspectJ pointcut language in its own AOP implementation. Spring’s implementation is not specifically targeted as a test solution.
Another technology is the use of a language that can create “advice” rules and be invoked via instrumentation. This is available in Byteman. Byteman uses Event Condition Action (ECA) rules.
Aspects and Mocks shown in full listings
- Exception verification using fault injection via AOP, http://octodecillion.com/blog/exception-verification-aop/
- Java testing using XStream, AspectJ, Vsdf, http://octodecillion.com/blog/java-test-xstream-serialization/
- Using AspectJ For Testing Legacy Code, http://octodecillion.com/blog/aopfortest/
- Java JMockIt mocks via Spring DI, http://octodecillion.com/blog/jmockit-mocks-via-spring/
- Why use an AOP language when other languages can now do Aspects?, http://octodecillion.com/blog/why-use-an-aop-language-when-other-languages-can-now-do-aspects/
- Aspect Oriented Programming with Spring
- Good book on AOP: AspectJ In Action, Second Edition, Ramniva Laddad.
- “Testing Object-Oriented Programs using Dynamic Aspects and Non-Determinism“, Michael Achenbach, Klaus Ostermann, accessed May 2013, http://www.cs.au.dk/~ma/papers/ach_et_al_etoos_2010.pdf.
- TwisteR, Dynamic Aspect Deployment for Ruby; http://twister.rubyforge.org/
- Kouhei Sakurai , “Test-based pointcuts: a robust pointcut mechanism based on unit test cases for software evolution,” in Proc. 2007 Proceedings of the workshop on Linking Aspect Technology and Evolution revisited., http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.144.8430
- Jasmine Spies, http://pivotal.github.io/jasmine/#section-Spies
- Using AspectJ For Testing Legacy Code
- Behavior counters for improved JUnit tests
- Use JMockit to Unit test logging output
- Java testing using XStream, AspectJ, Vsdf
- JMockIt method not found in type when using Invocation arg