Testing Applications with JUnit5 and JMock. Part 2
Trying to introduce JMock, we create the TestAccountService test using JMock, as in listing 5.
Into the listing we do the following:
- As always, we start the listing by importing all the necessary objects we need (1). As you can see, unlike EasyMock, the JMock framework doesn’t rely on any static import features.
- JUnit5 provides a programmatic way to register extensions. For JMock, this is done by annotating a JUnit5Mockery non-private instance field with @RegisterExtension. The context object serves us to create mocks and to define expectations (2).
- In (3) we declare the AccountManager which we want to mock. Like EasyMock, the core JMock framework only mocks interfaces.
- In the @BeforeEach method, which is executed before each of the @Test methods, we programmatically create the mock by means of the context object (4).
- As with any of the previous listings, we declare two accounts which we’ll use to transfer money in between (5).
- In (6) we start declaring the expectations, by constructing a new Expectations object.
- In (7) we declare the first expectation, each expectation having the form:
All the clauses are optional, except for the bold ones – invocation-count and mock-object. We need to specify how many invocations will occur and on which object. After that, in case the method returns an object, we can declare the return object by using the will(returnValue()) construction.
In (8) we start the transfer from the one account to the other, and after that we assert the expected results (9). It’s as simple as that!
But wait, what happened with the verification of the invocation count? In all of the previous examples we needed to verify that the invocations of the expectations happened the expected number of times. With JMock you don’t have to do that – the JMock extension takes care of this, and if any of the expected calls aren’t made the test fails.
The code snippet from listing 6 opens an HTTP connection to a given URL and reads the content at that URL. Suppose that this code is one method of a bigger application that you want to unit test.
In this listing:
- We open an HTTP connection (1)
- We read all the content that is received (2)
- If an error occurs, we return null (3)
What we want to test is the getContent method of the WebClient. For this purpose, we need to mock all the dependencies to that method. In this example we’ve two dependencies—one is the ConnectionFactory and one is the InputStream. Following the pattern with EasyMock, let’s try showing the WebClient test, this time using JMock.
- We start the test-case by registering the JMock extension. The JUnit5Mockery non-private instance field context is annotated with @RegisterExtension (1).
- To tell JMock to create mock objects not only for interfaces, but also for classes, we need to set the imposteriser property of the context (2). Now we can continue creating mocks the normal way.
- In (3) we declare and programmatically initialize the two objects we want to create mocks of.
- In (4) we start declaration of the expectations. Notice the fine way we declare the consecutive execution of the read() method of the stream (5), and also the returned values.
- In (6) we call the method under test and in (7) we assert the expected result.
- For a full view of how to use the JMock mocking library, we also provide another @Test method, which tests our WebClient under exceptional conditions. In (8) we declare the expectation of the close() method being triggered and in (9) we instruct JMock to raise an IOException when this trigger happens.
ConclusionsThis article has demonstrated the steps needed to test a Java application with the help of JUnit 5 and JMock. We showed how to test the functionality of an AccountService by mocking an AccountManager and of a WebClient by mocking a ConnectionFactory and an InputStream.
As you can see, the JMock library is as easy to use as the EasyMock one, but provides better integration with JUnit 5—we can programmatically register the Mockery context field. We still need to take a look at the third proposed framework: Mockito. We’re going to see that this one is closer to the JUnit 5 paradigm!
Interested in JUnit? Check out our trainings.
Java and Web Technologies Expert