Getting Started

In this simple example we are going to write a mock object test for a publish/subscribe message system. A Publisher sends messages to zero or more Subscribers. We want to test the Publisher, which involves testing its interactions with its Subscribers.

The Subscriber interface looks like this:

interface Subscriber {
    void receive(String message);
}

We will test that a Publisher sends a message to a single registered Subscriber. To test interactions between the Publisher and the Subscriber we will use a mock Subscriber object.

Set Up the Class Path

To use jMock 2.5.1 you must add the following JAR files to your class path:

Write the Test Case

First we must import the jMock classes, define our test fixture class and create a "Mockery" that represents the context in which the Publisher exists. The context mocks out the objects that the Publisher collaborates with (in this case a Subscriber) and checks that they are used correctly during the test.

Raw

import org.jmock.Mockery;
import org.jmock.Expectations;

class PublisherTest extends TestCase {
    Mockery context = new Mockery();
    ...    
}

This is a JUnit 3 test case but apart from the test case class the code will be the same when using any test framework for which jMock 2 does not have an integration layer.

JUnit 3

import org.jmock.integration.junit3.MockObjectTestCase;
import org.jmock.Expectations;

class PublisherTest extends MockObjectTestCase {
    ...    
}

JUnit 4

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4RuleMockery;

class PublisherTest {
    @Rule public JUnitRuleMockery context = new JUnitRuleMockery();
    ...
}

Note: this currently only works with the latest jMock release candidate (2.6.0RC1) and JUnit 4.7 and above.

In older versions of jMock and JUnit 4 you can use the JMock test runner, which is less flexible than the Rules mechanism shown above.

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4RuleMockery;

@RunWith(JMock.class)
class PublisherTest {
    Mockery context = new JUnit4Mockery();
    ...    
}

Now we want to write the method that will perform our test:

JUnit 3

public void testOneSubscriberReceivesAMessage() {
    ...
}

JUnit 4

@Test 
public void oneSubscriberReceivesAMessage() {
    ...
}

Raw

public void testOneSubscriberReceivesAMessage() {
    ...
}

We will now write the body of the test method.

We first set up the context in which our test will execute. We create a Publisher to test. We create a mock Subscriber that should receive the message. We then register the Subscriber with the Publisher. Finally we create a message object to publish.

JUnit 3

final Subscriber subscriber = mock(Subscriber.class);

Publisher publisher = new Publisher();
publisher.add(subscriber);

final String message = "message";

JUnit 4

final Subscriber subscriber = context.mock(Subscriber.class);

Publisher publisher = new Publisher();
publisher.add(subscriber);

final String message = "message";

Raw

final Subscriber subscriber = context.mock(Subscriber.class);

Publisher publisher = new Publisher();
publisher.add(subscriber);

final String message = "message";

Next we define expectations1 on the mock Subscriber that specify the methods that we expect to be called upon it during the test run. We expect the receive method to be called once with a single argument, the message that will be sent.

JUnit 3

checking(new Expectations() {{
    oneOf (subscriber).receive(message);
}});

JUnit 4

context.checking(new Expectations() {{
    oneOf (subscriber).receive(message);
}});

Raw

context.checking(new Expectations() {{
    oneOf (subscriber).receive(message);
}});

We then execute the code that we want to test.

publisher.publish(message);

After the code under test has finished our test must verify that the mock Subscriber was called as expected. If the expected calls were not made, the test will fail. The MockObjectTestCase does this automatically. You don't have to explicitly verify the mock objects in your tests. The JMock test runner does this automatically. You don't have to explicitly verify the mock objects in your tests.

context.assertIsSatisfied();

Here is the complete test.

JUnit 3

import org.jmock.integration.junit3.MockObjectTestCase;
import org.jmock.Expectations;

class PublisherTest extends MockObjectTestCase {
    public void testOneSubscriberReceivesAMessage() {
        // set up
        final Subscriber subscriber = mock(Subscriber.class);

        Publisher publisher = new Publisher();
        publisher.add(subscriber);
        
        final String message = "message";
        
        // expectations
        checking(new Expectations() {{
            oneOf (subscriber).receive(message);
        }});

        // execute
        publisher.publish(message);
    }
}

JUnit 4

import org.jmock.integration.junit4.JMock;
import org.jmock.integration.junit4.JUnit4Mockery;
import org.jmock.Expectations;

@RunWith(JMock.class)
class PublisherTest {
    Mockery context = new JUnit4Mockery();
    
    @Test 
    public void oneSubscriberReceivesAMessage() {
        // set up
        final Subscriber subscriber = context.mock(Subscriber.class);

        Publisher publisher = new Publisher();
        publisher.add(subscriber);
        
        final String message = "message";
        
        // expectations
        context.checking(new Expectations() {{
            oneOf (subscriber).receive(message);
        }});

        // execute
        publisher.publish(message);
    }
}

Raw

import org.jmock.Mockery;
import org.jmock.Expectations;

class PublisherTest extends TestCase {
    Mockery context = new Mockery();

    public void testOneSubscriberReceivesAMessage() {
        // set up
        final Subscriber subscriber = context.mock(Subscriber.class);

        Publisher publisher = new Publisher();
        publisher.add(subscriber);
        
        final String message = "message";
        
        // expectations
        context.checking(new Expectations() {{
            oneOf (subscriber).receive(message);
        }});

        // execute
        publisher.publish(message);
        
        // verify
        context.assertIsSatisfied();
    }
}

Where Next?

The jMock library is explored in more depth in other Cookbook recipes2. The Cheat Sheet3 is an overview of the entire jMock API.

Links:

1. expectations: http://www.jmock.org/expectations.html

2. other Cookbook recipes: http://www.jmock.org/cookbook.html

3. Cheat Sheet: http://www.jmock.org/cheat-sheet.html