Testing Applications with JUnit5 and EasyMock. Part 2
The second part of our article on testing applications with JUnit5 and EasyMock. This time we look at JUnit best practices, EasyMock object creation.
JUnit best practices: EasyMock object creation
Here’s a nice-to-know tip on the createMock method. If you check the API of EasyMock you see that the createMock method comes with numerous signatures. The signature that we use is:
Which one should we use? createMock(String name, Class claz) is better. If you use createMock(Class claz) and your expectations aren’t met, you get an error message like the following:
As you see this message isn’t as descriptive as we want it to be. If you use createMock(String name, Class claz) instead, and we map the class to a given name, we get something like the following:
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.
Listing 6 The WebClient class
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. It looks like there’s a problem because EasyMock can only mock interfaces and the InputStream is a class.
To be able to mock the InputStream class we need to use the class extensions of EasyMock. These represent an extension project of EasyMock which lets you generate mock objects for classes and interfaces. They’re addressed by the second Maven dependency from listing 1.
Listing 7 Testing WebClient with EasyMock
In listing 7 we do the following:
- We start by importing the objects that we need (1). Notice that because we use the class extensions of EasyMock, we now need to import the org.easymock.classextension.EasyMock object instead of org.easymock.EasyMock. Now we’re ready to create mock objects of classes and interfaces using the statically imported methods of the class extensions.
- In (2), as in the previous listings, we declare the objects which we want to mock, and in (3) we call the createMock method to initialize them.
- In (4) we define the expectation of the stream when the read method is invoked (notice that to stop reading from the stream, the last thing to return is a -1). Working with a low-level stream, we define how to read one byte at a time, as InputStream is reading byte by byte. In (5) we expect the close method to be called on the stream.
- Now we need to denote that we’re done by declaring our expectations – we do this by calling the replay method (6). The replay method is used to pass the mock from the phase where we record the method we expect to be called, to where we test. Before this, we recorded the behavior, but the object isn’t working as a mock. After calling replay, it works as expected. The rest is invoking the method under test (7), and asserting the expected result (8).
We also add another test to simulate a condition when we can’t close the InputStream.
- We define an expectation where we expect the close method of the stream to be invoked (9).
- Right on the next line we declare that an IOException should be raised if this call occurs (10).
Conclusions
This article has demonstrated the steps needed to test a Java application with the help of JUnit 5 and EasyMock. 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 the name of the framework suggests, using EasyMock is easy, and it’s an option for many projects, but to make you aware of the whole mocking picture, we need to introduce another framework, mocking parts of an account service and of a web client using three different mocking frameworks: EasyMock, JMock and Mockito. This way, you have a better taste on how the mocking works.