Download as pdf or txt
Download as pdf or txt
You are on page 1of 45

EasyMock

Testing Mediator Objects

copyright 2008 trainologic LTD


EasyMock

• Mediator Objects and Testing


• Introduction to Mock Objects
• Introduction to EasyMock
• Setting Expectations
• Mock Verification

copyright 2008 trainologic LTD


EasyMock

Testing Mediator Objects

• The JUnit testing framework, makes the testing of an


independent, non-void method, simple.
• But... how do we test an method with no return value?
• How do we test a method that interacts with other
domain objects?

3
copyright 2008 trainologic LTD
EasyMock

Testing Mediator Objects

• Let’s say we want to test a method that gets a


Collection and an Object, checks whether the Collection
contains the Object and only if it doesn’t, adds the
Object to the Collection.
• How would you implement this test?

4
copyright 2008 trainologic LTD
EasyMock

Testing Mediator Objects

• What if the method only gets a simple collection and


print it using a Logger?

5
copyright 2008 trainologic LTD
EasyMock

Testing Mediator Objects

• Many business objects that are really important to test


are mediators, i.e., they contain methods which
interact with other domain objects.

• Since in unit testing we want to test a unit without its


dependencies, we will have to eliminate them
somehow.
• We do this by passing dummy objects to “fill in” for the
real dependencies.

6
copyright 2008 trainologic LTD
EasyMock

Testing Mediator Objects

• These dummy objects are called Mock Objects.


• Which Mock Objects do we need for the add to
collection example?
• Which Mock Objects do we need for the print collection
example?

7
copyright 2008 trainologic LTD
EasyMock

• Mediator Objects and Testing


• Introduction to Mock Objects
• Introduction to EasyMock
• Setting Expectations
• Mock Verification

copyright 2008 trainologic LTD


EasyMock

Introduction to Mock Objects


• So... How “dumb” is a mock?
• First, it has to implement the same interface as the
original dependent object. Otherwise, the compiler
won’t let us pass it to the tested object.

• Second, it should supply the tested code with


everything it expects from the dependent object.

• Third, it should be able to check that the tested code is


using the dependent object (the Mock) correctly.

9
copyright 2008 trainologic LTD
EasyMock

Introduction to Mock Objects

• To use a Mock object we should:


• Create instance of the Mock.
• Set state and expectations.
• Invoke the tested code while passing the Mock as
parameter.
• Verify the Mock has been used correctly.

• Let’s see an example...

10
copyright 2008 trainologic LTD
EasyMock

Introduction to Mock Objects

• Let’s say we want to implement a special collection that


informs its listeners when and element is added to the
collection.

• That design is following the GoF Observer design


pattern.

11
copyright 2008 trainologic LTD
EasyMock

Introduction to Mock Objects

• To test this behavior we have to write the following


test:

@Test
public void testObservableCollection() {
Object objToAdd = new Object();
listenerMock.expect(1);
collection.addListener(listenerMock);
collection.add(objToAdd);
listenerMock.verify();
}

12
copyright 2008 trainologic LTD
EasyMock

Introduction to Mock Objects


• Let’s take a look at ListenerMock:

public class ListenerMock implements Listener {


private int counter;
private int expectedCounter;

public void elementAdded(){


counter++;
}

public void expect(int numOfCalls) {


expectedCounter = numOfCalls;
}
public void verify() {
if (counter != expectedCounter)
throw new AssertionFailedError();
}
}

13
copyright 2008 trainologic LTD
EasyMock

Introduction to Mock Objects

• As you can see, even though this is a very simple Mock,


it is cumbersome to write.

• It would have been much less pleasant if we had a


more complicated interface or if we had to check for
parameter values, return values and the order of
method calls.

14
copyright 2008 trainologic LTD
EasyMock

• Mediator Objects and Testing


• Introduction to Mock Objects
• Introduction to EasyMock
• Setting Expectations
• Mock Verification

copyright 2008 trainologic LTD


EasyMock

Introduction to EasyMock

• An open-source project providing an easy way to work


with Mock objects.

• Can be freely downloaded from easymock.org.


• Released under the MIT License.

16
copyright 2008 trainologic LTD
EasyMock

EasyMock - Benefits

• No need to write Mock objects by hand.


• Refactoring-safe, no need to refactor Mock in case the
interface has changed.
• Supports return values and Exceptions.
• Supports checking the order of calls for a single object
and for multiple projects.

• Uses a convenient record/replay mechanism.

17
copyright 2008 trainologic LTD
EasyMock

EasyMock - Installation

• Download EasyMock.
• Unzip the package.
• Add easymock.jar to your classpath.
• That is it!!!

18
copyright 2008 trainologic LTD
EasyMock

EasyMock

Create a Mock

19
copyright 2008 trainologic LTD
EasyMock

EasyMock

Create a Mock

Set Expectations

19
copyright 2008 trainologic LTD
EasyMock

EasyMock

Create a Mock

Set Expectations

Run Test

19
copyright 2008 trainologic LTD
EasyMock

EasyMock

Create a Mock

Set Expectations

Run Test

Verify

19
copyright 2008 trainologic LTD
EasyMock

EasyMock

• Let’s try to implement the same ListenerMock using


EasyMock.

@Test
public void testObservableCollection() {
mockListener = EasyMock.createMock(Listener.class);
//Recording
mockListener.elementAdded();
EasyMock.replay(mockListener);
//Playing
Object objToAdd = new Object();
collection.addListener(mockListener);
collection.add(objToAdd);
//Verifying
EasyMock.verify(mockListener);
}

20
copyright 2008 trainologic LTD
EasyMock

EasyMock

• No need to implement the Listener interface. The


implementation is being created by EasyMock on the
fly.

• After the creation of the Mock, EasyMock is in recording


mode.

• In the recording mode, we invoke methods of the Mock


and these method calls are recorded and used as
expectations.

21
copyright 2008 trainologic LTD
EasyMock

EasyMock

• The replay() method changes the mode from recording


to playing.

• Then the actual test is run and the Mock is being used
by the tested code.

• Finally, the verify() method makes sure the play was


identical to the recording.

22
copyright 2008 trainologic LTD
EasyMock

Creating Mock

• Creating a Mock is very easy... All we have to do is just


use the createMock() method and supply it with the
interface to implement.

Listener listenerMock = EasyMock.createMock(Listener.class);

23
copyright 2008 trainologic LTD
EasyMock

Creating Mock

• What happens if I don’t have an interface?


• Well... There are two options:
• Extract an interface;
• Use EasyMock Extension that works with classes as
well (separate download). The extension uses cglib to
dynamically create a sub-class.

• The next part of the chapter discus the expectation


settings and verification.

24
copyright 2008 trainologic LTD
EasyMock

• Mediator Objects and Testing


• Introduction to Mock Objects
• Introduction to EasyMock
• Setting Expectations
• Mock Verification

copyright 2008 trainologic LTD


EasyMock

Setting Expectations

• Setting expectations is mostly done by recording.


• But not everything can be recorded... A complementary
API enables us to refine our expectations.
• In the following example the Mock expects one call to
elementAdded() method.

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.elementAdded();
EasyMock.replay(listenerMock);

26
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Argument


Values
• In case there is a method argument, the Mock expects
an argument that equals() the argument in the
recording.

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.elementAdded(element);
EasyMock.replay(listenerMock);

27
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Number of


Calls
• If you want to expect more than one call, you can
either call the method several times in the recording
phase, or use the times() method.

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.elementAdded(element);
EasyMock.expectLastCall().times(3);
EasyMock.replay(listenerMock);

28
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Specifying


Return Values
• To specify what value is returned from a method call on
the Mock, use the expect(...).andReturn()

• During the playing phase, a call to getCallCount()


method will return 3.

listenerMock = EasyMock.createMock(Listener.class);
//Recording
EasyMock.expect(listenerMock.getCallCount()).andReturn(3);
EasyMock.replay(listenerMock);

29
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Specifying


Exception Throwing
• To specify that a method call on the Mock throws and
Exception, use the andThrow().

• During the playing phase, a call to getCallCount() will


throw a RuntimeException

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.getCallCount();
EasyMock.expectLastCall().andThrow(new RuntimeExcetion());
EasyMock.replay(listenerMock);

30
copyright 2008 trainologic LTD
EasyMock

Setting Expectations -
Combination
• We can combine all the options:

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.getCallCount();
EasyMock.expectLastCall()
.andReturn(3)
.times(2)
.andThrow(new RuntimeExcetion());
EasyMock.replay(listenerMock);

31
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Call Count

• By default, EasyMock fails if the count of the calls does


not match the exact number of call set in the recording.

• To change this behavior use times(), atLeastOnce() or


anyTimes()

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.getCallCount();
EasyMock.expectLastCall().times(2, 5); //At least 2 Max 5
EasyMock.expectLastCall().atLeastOnce(); //one or more
EasyMock.expectLastCall().anyTimes(); //zero or more
EasyMock.replay(listenerMock);

32
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Invocation


Order
• By default, EasyMock doesn’t check the order of
method calls.

• To change this behavior, you have to create a


StrictMock.

• We do that by calling the createStrictMock() method.


• StrictMocks check invocation orders on a single Mock.

listenerMock = EasyMock.createStrictMock(Listener.class);

33
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Invocation


Order
• If you want to verify invocation order that spans
several Mocks, you have to create a StrictControl and
use it to create the Mocks.

strictControl = EasyMock.createStrictControl();
listenerMock = strictControl.createMock(Listener.class);

34
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Argument


Matchers
• EasyMock expects arguments passed during the play
phase to be equals() to arguments being recorded.

• To have better control over argument values matching,


we use matchers.

• Matchers are simple methods that surround the


arguments during recording phase.

listenerMock = EasyMock.createMock(Listener.class);
//Recording
listenerMock.elementAdded(EasyMock.anyObject(element));
EasyMock.replay(listenerMock);

35
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Argument


Matchers
• There is a long list of available Matchers.
• All of them have self-descriptive names.
• In case you use matcher on one argument you must
use matchers on all arguments.

36
copyright 2008 trainologic LTD
EasyMock

Setting Expectations - Nice Mock

• If we have no expectations from the Mock and we only


want it to fill-in for the missing object and return
default values, we can create a “Nice Mock”.

• A nice Mock is a Mock which doesn’t care how we use


it.

• To create it, we simply call createNiceMock().

listenerMock = EasyMock.createNiceMock(Listener.class);

37
copyright 2008 trainologic LTD
EasyMock

• Mediator Objects and Testing


• Introduction to Mock Objects
• Introduction to EasyMock
• Setting Expectations
• Mock Verification

copyright 2008 trainologic LTD


EasyMock

Moving to Play Phase

• After setting all expectations, we change to play mode


and run our test code.

• Moving to play phase is done by calling the replay()


method and pass all Mocks as arguments.

EasyMock.replay(listenerMock);

39
copyright 2008 trainologic LTD
EasyMock

Moving to Play Phase

• During the play phase, EasyMock is tracking method


invocations on the Mocks.

• Even in case the invocations do not match the


expectations, EasyMock doesn’t fail the tests yet...

• There is still one more stage to go through...


Verification Stage.

40
copyright 2008 trainologic LTD
EasyMock

Verification

• After all test code finished executing, we want to check


that the Mock was used as we expected.

• To check this condition we simply call the verify()


method and pass all Mocks as arguments.

• In case one of our expectations is not fulfilled, an


exception is thrown and fails the test.

41
copyright 2008 trainologic LTD
EasyMock

Summary

• In order to unit-test isolated units we must use Mock


objects.

• Writing Mocks by hand is cumbersome.


• EasyMock is a simple and easy to use library that helps
us create Mock implementations on the fly.

• Expectation setting in EasyMock is done by applying


record/replay phases which provides great flexibility.

42
copyright 2008 trainologic LTD

You might also like