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:
- jmock-2.5.1.jar
- hamcrest-core-1.1.jar
- hamcrest-library-1.1.jar
- jmock-junit3-2.5.1.jar
- jmock-junit4-2.5.1.jar
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.JUnit4Mockery; @RunWith(JMock.class) class PublisherTest { Mockery context = new JUnit4Mockery(); ... }
Now we want to write the method that will perform our test:
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.
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.