Documentation for release 3.1 (2011-11-10)
© 2001-2011 OFFIS, Tammo Freese, Henri Tremblay.
EasyMock is a library that provides an easy way to use Mock Objects for given interfaces or classes. EasyMock is available under the terms of the Apache 2 license.
Mock Objects simulate parts of the behavior of domain code, and are able to check whether they are used as defined. Domain classes can be tested in isolation by simulating their collaborators with Mock Objects.
Writing and maintaining Mock Objects often is a tedious task that may introduce errors. EasyMock generates Mock Objects dynamically - no need to write them, and no generated code!
<dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.1</version> <scope>test</scope> </dependency>You can obviously use any other dependency tool compatible with the Maven repository.
easymock-3.1.zip
).easymock-3.1
directory.easymock.jar
) to your classpath.easymock-3.1-tests.jar
and can be launched with a JUnit TestRunner
having JUnit 4.7 on top of EasyMock, cglib and Objenesis in your classpath.easymock-3.1-sources.jar
.Most parts of a software system do not work in isolation, but collaborate with other parts to get their job done. In a lot of cases, we do not care about using collaborators in unit testing, as we trust these collaborators. If we do care about it, Mock Objects help us to test the unit under test in isolation. Mock Objects replace collaborators of the unit under test.
The following examples use the interface Collaborator
:
package org.easymock.samples; public interface Collaborator { void documentAdded(String title); void documentChanged(String title); void documentRemoved(String title); byte voteForRemoval(String title); byte[] voteForRemovals(String[] title); }
Implementors of this interface are collaborators
(in this case listeners) of a class named ClassUnderTest
:
public class ClassUnderTest { // ... public void addListener(Collaborator listener) { // ... } public void addDocument(String title, byte[] document) { // ... } public boolean removeDocument(String title) { // ... } public boolean removeDocuments(String[] titles) { // ... } }
The code for both the class and the interface may be found
in the package org.easymock.samples
in easymock-3.1-samples.jar
from the EasyMock zip delivery.
The following examples assume that you are familiar with the JUnit testing framework. Although the tests shown here use JUnit 4, you may as well use JUnit 3 or TestNG.
We will now build a test case and toy around with it to understand the
functionality of the EasyMock package. easymock-3.1-samples.jar
contains a modified version of this test. Our first test should check
whether the removal of a non-existing document does not lead to a notification
of the collaborator. Here is the test without the definition of the
Mock Object:
package org.easymock.samples; import org.junit.*; public class ExampleTest { private ClassUnderTest classUnderTest; private Collaborator mock; @Before public void setUp() { classUnderTest = new ClassUnderTest(); classUnderTest.addListener(mock); } @Test public void testRemoveNonExistingDocument() { // This call should not lead to any notification // of the Mock Object: classUnderTest.removeDocument("Does not exist"); } }
For many tests using EasyMock,
we only need a static import of methods of org.easymock.EasyMock
.
import static org.easymock.EasyMock.*; import org.junit.*; public class ExampleTest { private ClassUnderTest classUnderTest; private Collaborator mock; }
To get a Mock Object, we need to
Here is a first example:
@Before public void setUp() { mock = createMock(Collaborator.class); // 1 classUnderTest = new ClassUnderTest(); classUnderTest.addListener(mock); } @Test public void testRemoveNonExistingDocument() { // 2 (we do not expect anything) replay(mock); // 3 classUnderTest.removeDocument("Does not exist"); }
After activation in step 3, mock
is a Mock Object for the Collaborator
interface that expects no calls. This means that if we change
our ClassUnderTest
to call
any of the interface's methods, the Mock Object will throw
an AssertionError
:
java.lang.AssertionError: Unexpected method call documentRemoved("Does not exist"): at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentRemoved(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved(ClassUnderTest.java:74) at org.easymock.samples.ClassUnderTest.removeDocument(ClassUnderTest.java:33) at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument(ExampleTest.java:24) ...
Let us write a second test. If a document
is added on the class under test, we expect a call to mock.documentAdded()
on the Mock Object with the title of the document as argument:
@Test public void testAddDocument() { mock.documentAdded("New Document"); // 2 replay(mock); // 3 classUnderTest.addDocument("New Document", new byte[0]); }
So in the record state (before calling replay
),
the Mock Object does not behave like a Mock Object,
but it records method calls. After calling replay
,
it behaves like a Mock Object, checking whether the expected
method calls are really done.
If classUnderTest.addDocument("New Document", new byte[0])
calls the expected method with a wrong argument, the Mock Object will complain
with an AssertionError
:
java.lang.AssertionError: Unexpected method call documentAdded("Wrong title"): documentAdded("New Document"): expected: 1, actual: 0 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentAdded(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:61) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:28) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30) ...
All missed expectations are shown, as well as all fulfilled expectations for the unexpected call (none in this case). If the method call is executed too often, the Mock Object complains, too:
java.lang.AssertionError: Unexpected method call documentAdded("New Document"): documentAdded("New Document"): expected: 1, actual: 2 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentAdded(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded(ClassUnderTest.java:62) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:30) ...
There is one error that we have not handled so far: If we specify
behavior, we would like to verify that it is actually used. The current
test would pass if no method on the Mock Object is called. To verify that the
specified behavior has been used, we have to call
verify(mock)
:
@Test public void testAddDocument() { mock.documentAdded("New Document"); // 2 replay(mock); // 3 classUnderTest.addDocument("New Document", new byte[0]); verify(mock); }
If the method is not called on the Mock Object, we now get the following exception:
java.lang.AssertionError: Expectation failure on verify: documentAdded("New Document"): expected: 1, actual: 0 at org.easymock.internal.MocksControl.verify(MocksControl.java:70) at org.easymock.EasyMock.verify(EasyMock.java:536) at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:31) ...
The message of the exception lists all missed expectations.
Up to now, our test has only considered a single method call. The next
test should check whether the addition of an already existing
document leads to a call to mock.documentChanged()
with the appropriate argument. To be sure, we check this three
times (hey, it is an example ;-)):
@Test public void testAddAndChangeDocument() { mock.documentAdded("Document"); mock.documentChanged("Document"); mock.documentChanged("Document"); mock.documentChanged("Document"); replay(mock); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); verify(mock); }
To avoid the repetition of mock.documentChanged("Document")
,
EasyMock provides a shortcut. We may specify the call count with the method
times(int times)
on the object returned by
expectLastCall()
. The code then looks like:
@Test public void testAddAndChangeDocument() { mock.documentAdded("Document"); mock.documentChanged("Document"); expectLastCall().times(3); replay(mock); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); classUnderTest.addDocument("Document", new byte[0]); verify(mock); }
If the method is called too often, we get an exception that tells us that the method has been called too many times. The failure occurs immediately at the first method call exceeding the limit:
java.lang.AssertionError: Unexpected method call documentChanged("Document"): documentChanged("Document"): expected: 3, actual: 4 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.documentChanged(Unknown Source) at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged(ClassUnderTest.java:67) at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:26) at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43) ...
If there are too few calls, verify(mock)
throws an AssertionError
:
java.lang.AssertionError: Expectation failure on verify: documentChanged("Document"): expected: 3, actual: 2 at org.easymock.internal.MocksControl.verify(MocksControl.java:70) at org.easymock.EasyMock.verify(EasyMock.java:536) at org.easymock.samples.ExampleTest.testAddAndChangeDocument(ExampleTest.java:43) ...
For specifying return values,
we wrap the expected call in expect(T value)
and specify the return value
with the method andReturn(Object returnValue)
on the object returned by
expect(T value)
.
As an example, we check the workflow for document
removal. If ClassUnderTest
gets a call for document
removal, it asks all collaborators for their vote for removal
with calls to byte voteForRemoval(String title)
value.
Positive return values are a vote for
removal. If the sum of all values is positive, the document is removed
and documentRemoved(String title)
is called on
all collaborators:
@Test public void testVoteForRemoval() { mock.documentAdded("Document"); // expect document addition // expect to be asked to vote for document removal, and vote for it expect(mock.voteForRemoval("Document")).andReturn((byte) 42); mock.documentRemoved("Document"); // expect document removal replay(mock); classUnderTest.addDocument("Document", new byte[0]); assertTrue(classUnderTest.removeDocument("Document")); verify(mock); } @Test public void testVoteAgainstRemoval() { mock.documentAdded("Document"); // expect document addition // expect to be asked to vote for document removal, and vote against it expect(mock.voteForRemoval("Document")).andReturn((byte) -42); replay(mock); classUnderTest.addDocument("Document", new byte[0]); assertFalse(classUnderTest.removeDocument("Document")); verify(mock); }
The type of the returned value is checked at compile time. As an example, the following code will not compile, as the type of the provided return value does not match the method's return value:
expect(mock.voteForRemoval("Document")).andReturn("wrong type");
Instead of calling expect(T value)
to retrieve the object for setting the return value,
we may also use the object returned by expectLastCall()
.
Instead of
expect(mock.voteForRemoval("Document")).andReturn((byte) 42);
we may use
mock.voteForRemoval("Document"); expectLastCall().andReturn((byte) 42);
This type of specification should only be used if the line gets too long, as it does not support type checking at compile time.
For specifying exceptions (more exactly: Throwables) to be thrown, the object returned by
expectLastCall()
and expect(T value)
provides the method
andThrow(Throwable throwable)
.
The method has to be called in record state after the call to the Mock Object for
which it specifies the Throwable
to be thrown.
Unchecked exceptions (that is, RuntimeException
, Error
and all their subclasses) can be thrown from every method. Checked exceptions can only be
thrown from the methods that do actually throw them.
Sometimes we would like our mock object to return a value or throw an exception
that is created at the time of the actual call. Since EasyMock 2.2, the object returned by
expectLastCall()
and expect(T value)
provides the method
andAnswer(IAnswer answer)
which allows to specify an implementation of the
interface IAnswer
that is used to create the return value or exception.
Inside an IAnswer
callback, the arguments passed to the mock call
are available via EasyMock.getCurrentArguments()
.
If you use these, refactorings like reordering parameters may break your tests.
You have been warned.
An alternative to IAnswer
are the andDelegateTo
and
andStubDelegateTo
methods. They allow to delegate the call to a
concrete implementation of the mocked interface that will then provide the answer.
The pros are that the arguments found in EasyMock.getCurrentArguments()
for IAnswer
are now passed to the method of the concrete implementation.
This is refactoring safe. The cons are that you have to provide an implementation
which is kind of doing a mock manually... Which is what you try to avoid by
using EasyMock. It can also be painful if the interface has many methods. Finally,
the type of the concrete class can't be checked statically against the mock type.
If for some reason, the concrete class isn't implementing the method that is
delegated, you will get an exception during the replay only. However, this
case should be quite rare.
To understand correctly the two options, here is an example:
List<String> l = createMock(List.class); // andAnswer style expect(l.remove(10)).andAnswer(new IAnswer<String>() { public String answer() throws Throwable { return getCurrentArguments()[0].toString(); } }); // andDelegateTo style expect(l.remove(10)).andDelegateTo(new ArrayList<String>() { @Override public String remove(int index) { return Integer.toString(index); } });
It is also possible to specify a changing behavior for a method.
The methods times
, andReturn
, and andThrow
may be chained. As an example, we define voteForRemoval("Document")
to
RuntimeException
for the next four calls,
expect(mock.voteForRemoval("Document")) .andReturn((byte) 42).times(3) .andThrow(new RuntimeException(), 4) .andReturn((byte) -42);
To relax the expected call counts, there are additional methods
that may be used instead of times(int count)
:
times(int min, int max)
min
and max
calls,atLeastOnce()
anyTimes()
If no call count is specified, one call is expected. If we would like to state this
explicitely, once()
or times(1)
may be used.
On a Mock Object returned by a EasyMock.createMock()
,
the order of method calls is not checked.
If you would like a strict Mock Object that checks the order of method calls,
use EasyMock.createStrictMock()
to create it.
If an unexpected method is called on a strict Mock Object,
the message of the exception will show the method calls
expected at this point followed by the first conflicting one.
verify(mock)
shows all missing method calls.
Sometimes, it is necessary to have a Mock Object that checks the order of only some calls.
In record phase, you may switch order checking on by calling checkOrder(mock, true)
and switch it off by calling checkOrder(mock, false)
.
There are two differences between a strict Mock Object and a normal Mock Object:
To match an actual method call on the Mock Object with an
expectation, Object
arguments are by default compared with
equals()
. This may lead to problems. As an example,
we consider the following expectation:
String[] documents = new String[] { "Document 1", "Document 2" }; expect(mock.voteForRemovals(documents)).andReturn(42);
If the method is called with another array with the same contents,
we get an exception, as equals()
compares object
identity for arrays:
java.lang.AssertionError: Unexpected method call voteForRemovals([Ljava.lang.String;@9a029e): voteForRemovals([Ljava.lang.String;@2db19d): expected: 1, actual: 0 documentRemoved("Document 1"): expected: 1, actual: 0 documentRemoved("Document 2"): expected: 1, actual: 0 at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29) at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:44) at $Proxy0.voteForRemovals(Unknown Source) at org.easymock.samples.ClassUnderTest.listenersAllowRemovals(ClassUnderTest.java:88) at org.easymock.samples.ClassUnderTest.removeDocuments(ClassUnderTest.java:48) at org.easymock.samples.ExampleTest.testVoteForRemovals(ExampleTest.java:83) ...
To specify that only array equality is needed for this call, we may use the method
aryEq
that is statically imported from the EasyMock
class:
String[] documents = new String[] { "Document 1", "Document 2" }; expect(mock.voteForRemovals(aryEq(documents))).andReturn(42);
If you would like to use matchers in a call, you have to specify matchers for all arguments of the method call.
There are a couple of predefined argument matchers available.
eq(X value)
anyBoolean()
, anyByte()
, anyChar()
, anyDouble()
, anyFloat()
, anyInt()
, anyLong()
, anyObject()
, anyObject(Class clazz)
, anyShort()
eq(X value, X delta)
float
and double
.aryEq(X value)
Arrays.equals()
. Available for primitive and object arrays.isNull()
, isNull(Class clazz)
notNull()
, notNull(Class clazz)
same(X value)
isA(Class clazz)
lt(X value)
, leq(X value)
, geq(X value)
, gt(X value)
Comparable
.startsWith(String prefix), contains(String substring), endsWith(String suffix)
String
s.matches(String regex), find(String regex)
String
s.and(X first, X second)
first
and second
both match. Available for all primitive types and for objects.or(X first, X second)
first
and second
match. Available for all primitive types and for objects.not(X value)
value
does not match.cmpEq(X value)
Comparable.compareTo(X o)
. Available for all numeric primitive types and Comparable
.cmp(X value, Comparator<X> comparator, LogicalOperator operator)
comparator.compare(actual, value) operator 0
where the operator is <,<=,>,>= or ==. Available for objects.capture(Capture<T> capture)
, captureXXX(Capture<T> capture)
Capture
parameter for later access. You can do and(someMatcher(...), capture(c))
to
capture a parameter from a specific call to the method. You can also specify a CaptureType
telling that a given Capture
should keep
the first, the last, all or no captured values.Sometimes it is desirable to define own argument matchers. Let's say that an argument matcher is needed that matches an exception if the given exception has the same type and an equal message. It should be used this way:
IllegalStateException e = new IllegalStateException("Operation not allowed.") expect(mock.logThrowable(eqException(e))).andReturn(true);
Two steps are necessary to achieve this: The new argument matcher has to be defined,
and the static method eqException
has to be declared.
To define the new argument matcher, we implement the interface org.easymock.IArgumentMatcher
.
This interface contains two methods: matches(Object actual)
checks whether the actual argument
matches the given argument, and appendTo(StringBuffer buffer)
appends a string representation
of the argument matcher to the given string buffer. The implementation is straightforward:
import org.easymock.IArgumentMatcher; public class ThrowableEquals implements IArgumentMatcher { private Throwable expected; public ThrowableEquals(Throwable expected) { this.expected = expected; } public boolean matches(Object actual) { if (!(actual instanceof Throwable)) { return false; } String actualMessage = ((Throwable) actual).getMessage(); return expected.getClass().equals(actual.getClass()) && expected.getMessage().equals(actualMessage); } public void appendTo(StringBuffer buffer) { buffer.append("eqException("); buffer.append(expected.getClass().getName()); buffer.append(" with message \""); buffer.append(expected.getMessage()); buffer.append("\"")"); } }
The method eqException
must create the argument matcher with the given Throwable,
report it to EasyMock via the static method reportMatcher(IArgumentMatcher matcher)
,
and return a value so that it may be used inside the call
(typically 0
, null
or false
). A first attempt may look like:
public static Throwable eqException(Throwable in) { EasyMock.reportMatcher(new ThrowableEquals(in)); return null; }
However, this only works if the method logThrowable
in the example usage accepts
Throwable
s, and does not require something more specific like a RuntimeException
.
In the latter case, our code sample would not compile:
IllegalStateException e = new IllegalStateException("Operation not allowed.") expect(mock.logThrowable(eqException(e))).andReturn(true);
Java 5.0 to the rescue: Instead of defining eqException
with a Throwable
as
parameter and return value, we use a generic type that extends Throwable
:
public static <T extends Throwable> T eqException(T in) { reportMatcher(new ThrowableEquals(in)); return null; }
Mock Objects may be reset by reset(mock)
.
If needed, a mock can also be converted from one type to another by calling resetToNice(mock)
,
resetToDefault(mock)
ou resetToStrict(mock)
.
Sometimes, we would like our Mock Object to respond to some method calls, but we do not want to
check how often they are called, when they are called, or even if they are called at all.
This stub behavoir may be defined by using the methods andStubReturn(Object value)
,
andStubThrow(Throwable throwable)
, andStubAnswer(IAnswer<Tgt; answer)
and asStub()
. The following code
configures the MockObject to answer 42 to voteForRemoval("Document")
once
and -1 for all other arguments:
expect(mock.voteForRemoval("Document")).andReturn(42); expect(mock.voteForRemoval(not(eq("Document")))).andStubReturn(-1);
On a Mock Object returned by createMock()
the default behavior for all methods is to throw an
AssertionError
for all unexpected method calls.
If you would like a "nice" Mock Object that by default allows all method calls and returns
appropriate empty values (0
, null
or false
), use createNiceMock()
instead.
The behavior for the four Object methods equals()
,
hashCode()
, toString()
and finalize()
cannot be changed for Mock Objects created with EasyMock,
even if they are part of the interface for which the
Mock Object is created.
Up to this point, we have seen a mock object as a single object that is configured by static methods
on the class EasyMock
. But many of these static methods just identify the hidden control of the Mock Object
and delegate to it. A Mock Control is an object implementing the IMocksControl
interface.
So instead of
IMyInterface mock = createStrictMock(IMyInterface.class); replay(mock); verify(mock); reset(mock);
we may use the equivalent code:
IMocksControl ctrl = createStrictControl(); IMyInterface mock = ctrl.createMock(IMyInterface.class); ctrl.replay(); ctrl.verify(); ctrl.reset();
The IMocksControl allows to create more than one Mock Object, and so it is possible to check the order of method calls
between mocks. As an example, we set up two mock objects for the interface IMyInterface
, and we expect the calls
mock1.a()
and mock2.a()
ordered, then an open number of calls to mock1.c()
and mock2.c()
, and finally mock2.b()
and mock1.b()
, in this order:
IMocksControl ctrl = createStrictControl(); IMyInterface mock1 = ctrl.createMock(IMyInterface.class); IMyInterface mock2 = ctrl.createMock(IMyInterface.class); mock1.a(); mock2.a(); ctrl.checkOrder(false); mock1.c(); expectLastCall().anyTimes(); mock2.c(); expectLastCall().anyTimes(); ctrl.checkOrder(true); mock2.b(); mock1.b(); ctrl.replay();
Mock Objects can be named at creation using
createMock(String name, Class<T> toMock)
,
createStrictMock(String name, Class<T> toMock)
or
createNiceMock(String name, Class<T> toMock)
.
The names will be shown in exception failures.
Mocks can be serialized at any time during their life. However, there are some obvious contraints:
During recording, a mock is not thread-safe. So a giving mock (or mocks linked to the same IMocksControl
)
can only be recorded from a single thread. However, different mocks can be recorded simultaneously in different threads.
During the replay phase, mocks are by default thread-safe. This can be change for a given mock if makeThreadSafe(mock, false)
is called during the recording phase. This can prevent deadlocks in some rare situations.
Finally, calling checkIsUsedInOneThread(mock, true)
on a mock will make sure the mock is used in only one thread and
throw an exception otherwise. This can be handy to make sure a thread-unsafe mocked object is used correctly.
EasyMockSupport
is a class that meant to be used as a helper or base class to your test cases. It will automatically registers all
created mocks (or in fact all created controls) and to replay, reset or verify them in batch instead of explicitly. Here's a JUnit example:
public class SupportTest extends EasyMockSupport { private Collaborator firstCollaborator; private Collaborator secondCollaborator; private ClassTested classUnderTest; @Before public void setup() { classUnderTest = new ClassTested(); } @Test public void addDocument() { // creation phase firstCollaborator = createMock(Collaborator.class); secondCollaborator = createMock(Collaborator.class); classUnderTest.addListener(firstCollaborator); classUnderTest.addListener(secondCollaborator); // recording phase firstCollaborator.documentAdded("New Document"); secondCollaborator.documentAdded("New Document"); replayAll(); // replay all mocks at once // test classUnderTest.addDocument("New Document", new byte[0]); verifyAll(); // verify all mocks at once } }
EasyMock provides a property mecanisim allowing to alter its behavior. It mainly aims at allowing to use a legacy behavior on a new version. Currently supported properties are:
easymock.notThreadSafeByDefault
easymock.enableThreadSafetyCheckByDefault
easymock.disableClassMocking
Properties can be set in three ways. Each step in the list can overwrite previous ones.
easymock.properties
file set in the classpath default package
EasyMock.setEasyMockProperty
. Constants are available
in the EasyMock
class
EasyMock 3 still has a Class Extension project (although deprecated) to allow an easier migration from EasyMock 2 to EasyMock 3. It is a source not a binary compatibility. So the code will need to be recompiled.
EasyMock 2.1 introduced a callback feature that has been removed in EasyMock 2.2,
as it was too complex. Since EasyMock 2.2, the IAnswer
interface
provides the functionality for callbacks.
EasyMock jar can be used as an OSGi bundle. It exports org.easymock
,
org.easymock.internal
and org.easymock.internal.matchers
packages. However, to import the two latter, you need to specify the poweruser
attribute at true (poweruser=true
). These packages are meant to be
used to extend EasyMock so they usually don't need to be imported.
Sometimes you may need to mock only some methods of a class and keep the normal behavior of others. This usually happens when you want to test a method that calls some others in the same class. So you want to keep the normal behavior of the tested method and mock the others.
In this case, the first thing to do is to consider a refactoring since most of the time this problem caused by a bad design. If it's not the case or if you can't do otherwise because of some development constraints, here's the solution.
ToMock mock = createMockBuilder(ToMock.class) .addMockedMethod("mockedMethod").createMock();
In this case only the methods added with addMockedMethod(s)
will be
mocked (mockedMethod()
in the example). The others will still
behave as they used to. One exception: abstract methods are conveniently mocked by default.
createMockBuilder
returns a IMockBuilder
interface. It contains various methods to
easily create a partial mock. Have a look at the javadoc.
Remark: EasyMock provides a default behavior for Object's methods (equals, hashCode, toString, finalize). However, for a partial mock, if these methods are not mocked explicitly, they will have their normal behavior instead of EasyMock default's one.
It is possible to create a mock by calling one of its constructor. This can be handy when a class method needs to be tested but the class other methods, mocked. For that you should do something like
ToMock mock = createMockBuilder(ToMock.class) .withConstructor(1, 2, 3); // 1, 2, 3 are the constructor parameters
See the ConstructorCalledMockTest
for an example.
For some reason (usually an unsupported JVM), it is possible that EasyMock isn't able to mock a class mock in your environment. Under the hood, class instantiation is implemented with a factory pattern. In case of failure, you can replace the default instantiator with:
DefaultClassInstantiator
which works well with Serializable classes
and otherwise tries to guess the best constructor and parameters to use.IClassInstantiator
.
You set this new instantiator using ClassInstantiatorFactory.setInstantiator()
.
You can set back the default one with setDefaultInstantiator()
.
Important: The instantiator is kept statically so it will stick between your unit tests. Make sure you reset it if needed.
A class mock can also be serialized. However, since it extends a serializable class, this class
might have defined a special behavior using for instance writeObject
. These methods
will still be called when serializing the mock and might fail. The workaround is usually to call
a constructor when creating the mock.
Also, de-serializing the mock in a different class loader than the serialization might fail. It wasn't tested.
equals()
, toString()
, hashCode()
and finalize()
even for class mocking. It means that you cannot record your own behavior for
these methods. This limitation is considered to be a feature
that prevents you from having to care about these methods.
EasyMock has been developed by Tammo Freese at OFFIS. It is maintained by Henri Tremblay since 2007. The development of EasyMock is hosted on SourceForge to allow other developers and companies to contribute.
Class mocking (previously known as EasyMock Class Extension) was initially developed by Joel Shellman, Chad Woolley and Henri Tremblay on the files section of Yahoo!Groups.
Thanks to the people who gave feedback or provided patches, including Nascif Abousalh-Neto, Dave Astels, Francois Beausoleil, George Dinwiddie, Shane Duan, Wolfgang Frech, Steve Freeman, Oren Gross, John D. Heintz, Dale King, Brian Knorr, Dierk Koenig, Chris Kreussling, Robert Leftwich, Patrick Lightbody, Johannes Link, Rex Madden, David McIntosh, Karsten Menne, Bill Michell, Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Markus Schmidlin, Richard Scott, Joel Shellman, Jiří Mareš, Alexandre de Pellegrin Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Bill Uetrecht, Frank Westphal, Chad Woolley, Bernd Worsch, Rodrigo Damazio, Bruno Fonseca, Ben Hutchison and numerous others.
Please check the EasyMock home page for new versions, and send bug reports and suggestions to the EasyMock Yahoo!Group. If you would like to subscribe to the EasyMock Yahoo!Group, send a message to easymock-subscribe@yahoogroups.com.
New in version 3.1:
New in version 3.0:
EasyMock.DISABLE_CLASS_MOCKING
toString
method (2937916)
isNull(Class<T>)
, notNull(Class<T>)
and anyObject(Class<T>)
for easier generic handling (2958636)
For older release notes, see EasyMock 2 and EasyMock 2 Class Extension documentations.