## EasyMock 1.2_Java1.3 Readme

Documentation for release 1.2_Java1.3 (August 7 2005)
© 2001-2005 OFFIS.

EasyMock is a class library that provides an easy way to use Mock Objects for given interfaces. EasyMock is available under the terms of the MIT 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!

### EasyMock Benefits

- Hand-writing classes for Mock Objects is not needed.
- Supports return values and exceptions.
- Supports changing results for the same method call.
- Supports call count checking.
- Supports default values for method calls.
- Supports checking the order of method calls.

### EasyMock Drawbacks

- EasyMock does only work with Java 2, 1.3.1 and above.

EasyMock by default supports the generation of Mock Objects for interfaces only. For those who would like to generate Mock Objects for classes, there is an extension available at the EasyMock home page.

## Installation

1. Java (at least 1.3.1) is required.
2. JUnit (at least 3.8.1) has to be in the class path.
3. Unzip the EasyMock zip file (`easymock1.2_Java1.3.zip`). It contains a directory `easymock1.2_Java1.3`. Add the EasyMock jar file (`easymock.jar`) from this directory to your classpath.

To execute the EasyMock tests, add `tests.zip` to your class path and start `'java org.easymock.tests.AllTests'`.

The source code of EasyMock is stored in the zip file `src.zip`.

## Usage

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 `samples.zip`.

The following examples assume that you are familiar with the JUnit testing framework.

### The first Mock Object

We will now build a test case and toy around with it to understand the functionality of the EasyMock package. `samples.zip` 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 junit.framework.TestCase;

    public class ExampleTest extends TestCase {

        private ClassUnderTest classUnderTest;
        private Collaborator mock;

        protected void setUp() {
            classUnderTest = new ClassUnderTest();
            classUnderTest.addListener(mock);
        }

        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 to import one class: `org.easymock.MockControl` (in fact, EasyMock has only two non-internal classes and one non-internal interface!).

    import org.easymock.MockControl;

    public class ExampleTest extends TestCase {

        private ClassUnderTest classUnderTest;
        private MockControl control;
        private Collaborator mock;

    }

To get a usable Mock Object, we need to

1. get a `MockControl` for the interface we would like to simulate,
2. get the Mock Object from the `MockControl`,
3. specify the behavior of the Mock Object (record state)
4. activate the Mock Object via the control (replay state).

Sounds difficult? It isn't:

        protected void setUp() {
            control = MockControl.createControl(Collaborator.class); // 1
            mock = (Collaborator) control.getMock(); // 2
            classUnderTest = new ClassUnderTest();
            classUnderTest.addListener(mock);
        }

        public void testRemoveNonExistingDocument() {
            // 3 (we do not expect anything)
            control.replay(); // 4
            classUnderTest.removeDocument("Does not exist");
        }

After activation in step 4, `mock` is a Mock Object for the `Collaborator` interface that expects no calls. This means that if we change our class under test to call any of the interface's methods, the Mock Object will throw an `AssertionFailedError`:

    junit.framework.AssertionFailedError:
      Unexpected method call documentRemoved("Does not exist"):
        documentRemoved("Does not exist"): expected: 0, actual: 1
    	at org.easymock.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:41)
    	at $Proxy0.documentRemoved(Unknown Source)
    	at org.easymock.samples.ClassUnderTest.notifyListenersDocumentRemoved
    (ClassUnderTest.java:78)
    	at org.easymock.samples.ClassUnderTest.removeDocument
    (ClassUnderTest.java:34)
    	at org.easymock.samples.ExampleTest.testRemoveNonExistingDocument
    (ExampleTest.java:27)
        // ...

### Adding Behavior

Now we 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:

        public void testAddDocument() {
            mock.documentAdded("New Document"); // 3
            control.replay(); // 4
            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 `AssertionFailedError`:

    junit.framework.AssertionFailedError:
      Unexpected method call documentAdded("Wrong title"):
        documentAdded("Wrong title"): expected: 0, actual: 1
        documentAdded("New Document"): expected: 1, actual: 0
        at org.easymock.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:41)
        at $Proxy0.documentAdded(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded
    (ClassUnderTest.java:63)
        at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:29)
        at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:33)
    // ...

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:

    junit.framework.AssertionFailedError:
      Unexpected method call documentAdded("New Document"):
        documentAdded("New Document"): expected: 1, actual: 2
        at org.easymock.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:41)
        at $Proxy0.documentAdded(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentAdded
    (ClassUnderTest.java:64)
        at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:30)
        at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:33)
        // ...

### Verifying Behavior

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 `control.verify()`:

        public void testAddDocument() {
            mock.documentAdded("New Document"); // 3
            control.replay(); // 4
            classUnderTest.addDocument("New Document", new byte[0]);
            control.verify();
        }

If the method is not called on the Mock Object, we now get the following exception:

    junit.framework.AssertionFailedError:
      Expectation failure on verify:
        documentAdded("New Document"): expected: 1, actual: 0
        at org.easymock.AbstractBehavior.verify(AbstractBehavior.java:74)
        at org.easymock.PlayState.verify(PlayState.java:23)
        at org.easymock.MockControl.verify(MockControl.java:153)
        at org.easymock.samples.ExampleTest.testAddDocument(ExampleTest.java:34)
        // ...

The message of the exception lists all the missed expectations.

### Expecting an Explicit Number of Calls

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 ;-)):

        public void testAddAndChangeDocument() {
            mock.documentAdded("Document");
            mock.documentChanged("Document");
            mock.documentChanged("Document");
            mock.documentChanged("Document");
            control.replay();
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            control.verify();
        }

To avoid the repetition of `mock.documentChanged("Document")`, EasyMock provides a shortcut. The method `setVoidCallable(int times)` on `MockControl` allows us to set the expected call count:

        public void testAddAndChangeDocument() {
            mock.documentAdded("Document");
            mock.documentChanged("Document");
            control.setVoidCallable(3);
            control.replay();
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            classUnderTest.addDocument("Document", new byte[0]);
            control.verify();
        }

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:

    junit.framework.AssertionFailedError:
      Expectation failure on method call documentChanged("Document"):
        documentChanged("Document"): expected: 3, actual: 4
        at org.easymock.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:41)
        at $Proxy0.documentChanged(Unknown Source)
        at org.easymock.samples.ClassUnderTest.notifyListenersDocumentChanged
    (ClassUnderTest.java:71)
        at org.easymock.samples.ClassUnderTest.addDocument(ClassUnderTest.java:23)
        at org.easymock.samples.ExampleTest.testAddAndChangeDocument
    (ExampleTest.java:46)
        // ...

If there are too few calls, `control.verify()` throws an `AssertionFailedError`:

    junit.framework.AssertionFailedError:
      Expectation failure on verify:
        documentChanged("Document"): expected: 3, actual: 2
        at org.easymock.PlayState.verify(PlayState.java:24)
        at org.easymock.MockControl.verify(MockControl.java:153)
        at org.easymock.samples.ExampleTest.testAddAndChangeDocument
    (ExampleTest.java:45)

### Strict Mocks

On a Mock Object returned by a `MockControl` created with `MockControl.createControl()`, the order of method calls is not checked. If you would like a "strict" Mock Object that checks the order of method calls, use `MockControl.createStrictControl()` to create its `MockControl`.

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()` shows all missing method calls.

### Specifying Return Values

For specifying return values, the `MockControl` provides the methods `setReturnValue([type] value)` and `setReturnValue([type] value, int times)`. `[type]` is either `Object` or a primitive type. These methods have to be called in record state after the call to the Mock Object for which they specify the return 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:

        public void testVoteForRemoval() {
            mock.documentAdded("Document");   // expect document addition
            mock.voteForRemoval("Document");  // expect to be asked to vote ...
            control.setReturnValue(42);       // ... and vote for it
            mock.documentRemoved("Document"); // expect document removal
            control.replay();
            classUnderTest.addDocument("Document", new byte[0]);
            assertTrue(classUnderTest.removeDocument("Document"));
            control.verify();
        }

        public void testVoteAgainstRemoval() {
            mock.documentAdded("Document");   // expect document addition
            mock.voteForRemoval("Document");  // expect to be asked to vote ...
            control.setReturnValue(-42);      // ... and vote against it
            control.replay();
            classUnderTest.addDocument("Document", new byte[0]);
            assertFalse(classUnderTest.removeDocument("Document"));
            control.verify();
        }

### Working with Exceptions

For specifying exceptions (more exact: Throwables) to be thrown, the control provides the methods `setThrowable(Throwable throwable)` and `setThrowable(Throwable throwable, int times)`. These methods have to be called in record state after the call to the Mock Object for which they specify 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.

### Relaxing Call Counts

The `MockControl` provides different methods for specifying expected call counts. To expect a fixed number of calls, we already know

- `setReturnValue([type], int times)`
- `setThrowable(Throwable throwable, int times)`
- `setVoidCallable(int times)`.

To expect exactly one call, there are

- `setReturnValue([type])`
- `setThrowable(Throwable throwable)`
- `setVoidCallable()`.

The last method is implicitly assumed in record state for calls to methods with `void` return type which are followed by another method call on the Mock Object, or by `control.replay()`.

To relax the expected call counts, there are additional methods. The first group of them sets as expectation that a method is called between `minCount` and `maxCount` times:

- `setReturnValue([type], int minCount, int maxCount)`
- `setThrowable(Throwable throwable, int minCount, int maxCount)`
- `setVoidCallable(int minCount, int maxCount)`.

The second group allows to specify an expected `Range` of calls. Three `Range` objects are available: `MockControl.ONE` expects exactly one call, `MockControl.ONE_OR_MORE` expects one or more calls and `MockControl.ZERO_OR_MORE` any number of calls:

- `setReturnValue([type], Range range)`
- `setThrowable(Throwable throwable, Range range)`
- `setVoidCallable(Range range)`.

### Changing Behavior for the Same Method Call

It is also possible to specify a changing behavior for a method. As an example, we define `voteForRemoval("Document")` to

- return 42 for the first three calls,
- throw a `RuntimeException` for the next four calls,
- return -42 for all subsequent calls:

        mock.voteForRemoval("Document");
        control.setReturnValue(42, 3);
        control.setThrowable(new RuntimeException(), 4);
        control.setReturnValue(-42, MockControl.ZERO_OR_MORE);

### Convenience Methods for Return Values

Convenience methods allow to specify an expected method call and a return value in one line of code. Instead of writing

        mock.voteForRemoval("Document");
        control.setReturnValue(42);

we may use

        control.expectAndReturn(mock.voteForRemoval("Document"), 42);

As the `setReturnValue()` methods, the convenience methods are available for unspecified call counts, for `Range` call counts, for call counts of type `int` as well as for call counts between a minimum and a maximum.

For the `setDefaultReturnValue()` methods, there are convenience methods named `expectAndDefaultReturn`.

### Convenience Methods for Throwables

Convenience methods allow to specify an expected method call and a throwable to throw in one line of code. Instead of writing

        mock.aMethod(12);
        control.setThrowable(new Error());

we may use

        control.expectAndThrow(mock.aMethod(12), new Error());

However, this form does only work for methods with a return type other than `void`.

As the `setThrowable()` methods, the convenience methods are available for unspecified call counts, for `Range` call counts, for call counts of type `int` as well as for call counts between a minimum and a maximum.

For the `setDefaultThrowable()` methods, there are convenience methods named `expectAndDefaultThrow`.

### Arguments Matchers

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:

        mock.voteForRemoval(new String[] {"Document 1", "Document 2"});
        control.setReturnValue(12);

If the method is called with another array with the same contents, we get an exception, as `equals()` compares object identity for arrays:

    junit.framework.AssertionFailedError:
      Expectation failure on method call voteForRemovals([Ljava.lang.String;@b66cc):
        voteForRemovals([Ljava.lang.String;@1546e25): expected: 1, actual: 0

To set another matcher, EasyMock provides the method `setMatcher(ArgumentsMatcher matcher)` on `MockControl`. To redefine a matcher for a method, we have to call `setMatcher()` immediately after the first call to the method.

There are three predefined matchers in EasyMock:

1. `MockControl.EQUALS_MATCHER`: The default matcher that uses `equals()` for object comparison, and `==` for primitive type comparison.
2. `MockControl.ARRAY_MATCHER`: Matches array arguments with `Arrays.equals()`, behaves like `MockControl.EQUALS_MATCHER` for other arguments.
3. `MockControl.ALWAYS_MATCHER`: Matches always.

To match our array expectation, we use `MockControl.ARRAY_MATCHER`:

        mock.voteForRemovals(new String[] {"Document 1", "Document 2"});
        control.setMatcher(MockControl.ARRAY_MATCHER);
        control.setReturnValue(42);

To redefine the default matcher that is used for all methods on the Mock Object, we may call `setDefaultMatcher(ArgumentsMatcher matcher)` on `MockControl` directly after Mock Object creation.

        control.setDefaultMatcher(MockControl.ARRAY_MATCHER);
        mock.voteForRemovals(new String[] {"Document 1", "Document 2"});
        control.setReturnValue(42);

### Arguments Matchers and Error Messages

The interface `ArgumentsMatcher` has two methods:

        boolean matches(Object[] expected, Object[] actual);
        String toString(Object[] arguments);

The first method is used to decide whether arguments match. The second method is called to provide a string representation of the arguments in case of an error. This allows us to provide better error messages. Here is an example for a comparison failure with `MockControl.ARRAY_MATCHER`:

    junit.framework.AssertionFailedError:
      Unexpected method call voteForRemovals(["Document 1", "Document 3"]):
        voteForRemovals(["Document 1", "Document 3"]): expected: 0, actual: 1
        voteForRemovals(["Document 1", "Document 2"]): expected: 1, actual: 0

### Defining own Arguments Matchers

To define own arguments matchers, the abstract class `AbstractMatcher` is provided. A subclass of it that does not redefine any method will behave like `MockControl.EQUALS_MATCHER`. The class provides two additional methods:

        protected boolean argumentMatches(Object expected, Object actual) {
        protected String argumentToString(Object argument) {

These methods allow the redefinition of matching and string representation of each argument. As an example, we provide an implementation of a matcher that only compares the first char for each string argument. For each string, only the first char followed by dots is displayed:

    public class FirstCharMatcher extends AbstractMatcher {
        protected boolean argumentMatches(Object first, Object second) {
            if (first instanceof String) {
                first = first(first);
            }
            if (second instanceof String) {
                second = first(second);
            }
            return super.argumentMatches(first, second);
        }

        protected String argumentToString(Object argument) {
            if (argument instanceof String) {
                argument = first(argument) + "...";
            }
            return super.argumentToString(argument);
        }

        private String first(Object string) {
            String first = (String) string;
            if (first == null || first.length() == 0) {
                return first;
            }
            return first.substring(0, 1);
        }
    }

### Incorrect EasyMock Usage

Our test may use the EasyMock library in an incorrect way. For example, it may specify a non-compatible return value, or call verify() in record state. In these cases, EasyMock will complain with an appropriate exception at runtime.

### Reusing a Mock Object

Mock Objects may be reset by `control.reset()`.

### Using Default Behavior for Methods

The default behavior for each method is to throw an `AssertionFailedError`. This can be changed by calling `setDefaultReturnValue()`, `setDefaultThrowable()` or `setDefaultVoidCallable()` in the record state. The following code configures the MockObject to answer 42 to `voteForRemoval("Document")` once and -1 for subsequent calls as well as all other arguments to `voteForRemoval()`:

        mock.voteForRemoval("Document");
        control.setReturnValue(42);
        control.setDefaultReturnValue(-1);

### Nice Mocks

On a Mock Object returned by a `MockControl` created with `MockControl.createControl()`, the default behavior for all methods is to throw an `AssertionFailedError`. 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 `MockControl.createNiceControl()` to create its `MockControl`.

### Object Methods

The behavior for the three object methods `equals()`, `hashCode()` and `toString()` cannot be changed for Mock Objects created with EasyMock, even if they are part of the interface for which the Mock Object is created.

## EasyMock Development

EasyMock 1.0 has been developed by Tammo Freese at OFFIS. The development of EasyMock is now hosted on SourceForge to allow other developers and companies to contribute.

Thanks to the people who gave feedback: 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, Johannes Link, Rex Madden, David McIntosh, Karsten Menne, Stephan Mikaty, Ivan Moore, Ilja Preuss, Justin Sampson, Richard Scott, Joel Shellman, Shaun Smith, Marco Struck, Ralf Stuckert, Victor Szathmary, Henri Tremblay, Bill Uetrecht, Frank Westphal, Chad Woolley, Bernd Worsch, 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.

EasyMock Version 1.2_Java1.3 (August 7 2005)

Changes since 1.1:

- EasyMock is released in two versions: One for Java 1.3 and above, and one for Java 1.5 with VarArgs support and better type safety.
- order of arguments for ArgumentsMatcher is like in EasyMock 1.0 now
- stack traces are now only cut if the exception is thrown from EasyMock
- convenience methods `expectAndDefaultReturn()` and `expectAndDefaultThrow()` allow setting default return values and throwables in one line of code
- `hashCode()` implementation is changed for better performance
- added Clover coverage reports

Changes since 1.0.1b:

- A first extension for EasyMock is available. With the help of cglib, it allows generating mock objects for classes. It is available in an own jar file from the EasyMock home page.
- ParameterMatcher renamed to ArgumentsMatcher, since it matches arguments, not parameters
- parameterMatches() and parameterToString() on AbstractMatcher renamed to argumentMatches() and argumentToString(), since they work on arguments, not parameters
- tests extended to gain 100% clover coverage
- internal refactorings

Changes since 1.0.1:

- src.zip now contains the classes of the package org.easymock.internal

Changes since 1.0:

- refactoring to open EasyMock for extensions
- convenience methods `expectAndReturn() and expectAndThrow()`

Changes since 0.8:

- added strict EasyMocks that check order of method calls
- added Ranges that allow to specify a range of allowed calls
- added ParameterMatcher that allows to specify how parameters are matched
- Added JavaDoc
- Better error messages
- changed behavior for unspecified call count: instead of assuming one of more calls, exactly one is expected
- deprecated activate(), its name is now replay()
- MockControl is now an abstract class, Deprecated EasyMock.controlFor(), it is now MockControl.createControl(), Deprecated EasyMock.niceControlFor(), it is now MockControl.createNiceControl()
- InvalidMockUsageException replaced with appropriate exceptions from java: IllegalStateException, NullPointerException, IllegalArgumentException
- hashCode(), equals() and toString() now also work in setup state
- hashCode() returns the hashCode of the String returned by toString()
- many refactorings