Introduction

The purpose of this document is to compare and contrast the jMock (http//www.jmock.org) API with the VirtualMock API.

JMock differs from VirtualMock in at least two fundamental implementation approaches:

  • Object-Based vs. Class-Based Mocks: Mocks are based on dynamic proxies vs AOP/Bytecode manipulation (virtual mocks). This can also be considered more generically as "object-based" vs. "class-based" mocks. Both approaches have their benefits and limitations.
  • One-Expression vs. Record-and-Playback expectation definition: JMock uses the "one-expression" approach of defining expectations. This includes hardcoding the name of the method to be expected as a string literal. VirtualMock uses the "record-and-playback" approach, where actual method calls on the mock are used to define expectations. The approach is a matter of preference. Personally, I prefer the VirtualMock approach, if only because it allows automatic code completion through the IDE when defining expected method calls. Also, some IDEs or tools may not recognize the string literal method names when doing automated refactoring, or when searching for references to a given method.

The choice between these two fundamental implementation approaches will be largely determined by personal preference, or by the user's individual situation. Also, since these two approaches are for the most part mutually independent, users may want to "mix-and-match" to their preference. For example, using Object-based mocks with the Record-and-Playback expectation definition, or Class-Based mocks with the One-Expression approach.

Thus, the main goal of this document is to explore the possibility of reusing components from both frameworks to allow users the flexibility to choose the features that are most useful to them, regardless of which framework they are part of.

The remaining sections are detailed comparisons of how basic mock object concepts are implemented in both frameworks.

Invocation vs. Call

This is the core data object which is used to represent a method invocation.

Analysis

jMock uses the Invocation class. VirtualMock uses a superclass Call, with two subclasses, RecordedCall and InvokedCall. RecordedCall is the most similar in concept to Invocation.

First of all, Invocation is probably a better name than Call - a topic Nat has explored on his blog http://nat.truemesh.com/archives/000151.html. However, because of implementation differences (see below), they should remain named independently to prevent conflicts if the two frameworks are used together.

In VirtualMock, the method signature is abstracted into a Signature class, while the values (argument values and return values/exception values) are in the Call. In jMock, the signature and values are combined into the Invocation.

The abstraction of the Signature is useful (and, in the current VirtualMock API, necessary), for the implementation of virtual (class-based) mocks. This is because the identification of a call by the aspect framework is based on the method signature (MethodJoinPoint in AspectWerkz, and CodeSignature in AspectJ). This can be observed in the VirtualMock methods AspectjAspectUtils.getSignatureFromJoinPoint() and AspectWerkzAspectUtils.getSignatureFromMethodJoinPoint(). The matching of argument values is independent, and performed later in the processing. The single-class Invocation approach of jMock could be used, but this would unnecessarily complicate portions of VirtualMock, including the Record-and-Playback approach, where the identification of a "record" call is initially independent of the argument values.

The fact that the jMock Invocation is a concrete class instead of an interface is also problematic. This locks us in to the jMock implementation, which is currently incompatible with VirtualMock, as mentioned above.

Impact

Since Invocation is a concrete class (not an interface), and also is used throughout the jMock API (in StatelessInvocationMatcher, for example), this prevents the use of much of the jMock API in other frameworks which do not use the jMock implementation of Invocation.

Action

One solution would be if jMock abstracted out the concept of a "Method Signature" from the Invocation, and created interfaces for both.

An alternate solution (and a much simpler one, for jMock) would be to simply extract an interface for Invocation. This would allow an InvocationAdapter to be written for VirtualMock's RecordedCall. InvocationAdapter would implement the Invocation interface, and thus allow the use of the jMocks matching capabilities, such as StatelessInvocationMatcher and it's subclasses.