How to Mock Final Classes in Unit Tests
Mocking has become a key component to writing effective unit-tests. It is a very useful strategy to write focused tests. Mocking frameworks make it easy to write test, but they have their limitations. Both Mockito and EasyMock cannot mock classes (or methods) that are final. This article will show you how to mock such classes while continuing to use your favorite mocking framework (Mockito for the sake of this article).
In a future article, I will extend this strategy to writing unit tests for Google Web Toolkit (GWT) without the need of the GWTTestCase.
Provide a framework that can mock final classes, while using an existing mocking framework. For this, I have implemented PreMock.
- Refactor – Refactoring the code you need to mock (so it can be mocked) can be the best solution. Extracting an interface, making a method not final, etc. are all valid options. However, it is not always practical, the class you need to mock could be within a 3rd party library. Also, rewriting a class to make it easier to test, may expose more to your API than desired. Furthermore, I am not a fan of adding boiler plate wrapping classes, just to support unit testing (if it can be avoided). The less code you need to write, the easier it is to maintain.
- Don’t Mock – Mocking isn’t always necessary, and sometimes it is not the best choice. For example, instead of mocking your persistence tier for testing your services, provide a persistence tier that can be used within unit tests. See Unit Testing Your Persistence Tier Code.
- Powermock – There is already an open-source library out there that provides a way to mock final classes. I had difficultlies getting it configured for the tests I needed. Also, it could not be extended to create the desired tests for GWT (this is something I plan on covering in a future article).
Alter the class, with byte code manipulation, as it is being loaded by a custom class loader. During loading of the class remove the final modifier. When the class is loaded to Mockito it will be a non-final class.
- Get the class loader in place so that any class referenced in the unit test will use by the class loader; allow for our unit-test to be written like any other unit test.
- Alter the byte code of the java class when it is being loaded.
- Make sure that classes that should not be modified, are not modified.
- Java 6 – I’m sure Java 5 and Java 7 would work, provided the versions of JUnit, Mockito, and Javassist also worked with the desired version of Java.
- JUnit 4.10 – Junit has gone over some major tranformations in regards to the test runner. Mockito, Spring, and others frameworks provide test runners for making writing unit tests easier. Here we will write a test runner than will allow us to mock those classes and methods that Mockito and Easymock cannot test. Versions since 4.8.2 should work, and I expect versions since 4.7 will also work. The runner changed between version 4.6 and 4.7, so I believe 4.6 and earlier versions of JUnit will not work.
- Mockito 1.9.0 – I am sure this can be applied to older versions of Mockito and other versions of Easymock. While I have used EasyMock longer, I find Mockito easier to use. Mockito has its own JUnit test runner; it will be incorporated into the test runner described here, since I don’t want to loose it’s functionality. I have also tested against version 1.8.5
- Javassist 3.15 – Bytecode manipulation is the key component to removing the final modifier. I’m sure ASM would also work, but personally, I like Javassist. I did some testing against an older version of 3.4, and it worked fine.
This solution can be found on github as an Eclipse Project, see PreMock. Only 3 classes are needed for PreMock, and they are:
This annotation will be used within the JUnit test to determine which classes can be pre-mocked. This will insure we do not alter a class unexpectedly; only the unit test and classes listed here are loaded by the custom class loader.
Using javassist, this classloader will do byte-code manipulation to remove the annoying final modifier. While the use of javassist here is very light, when I expand on PreMock for GWT testing, javassist will be utilized more. This class-loader will pass all classes to the parent class loader, except for the unit test and the classes annotated in @PreMock.
JUnit does not provide a way to change the class loader, so this ParentRunner does the trick. It reloads the unit test with our custom class loader, and then swaps it in. Once JUnit uses the custom class loader for our test class, we are all set. Please read the comments in the code to understand how this swap takes place. Also, the code provided in the Mockito Test Runner is included, since you can only have one Parent Runner. Mockito’s Runner is what allows the @Mock and @InjectMocks to work.
Here is a unit test that successfully tests a final class with a final method. To see it fail due a final class, simply replace PreMock in the @RunsWith with Mockito’s.
I hope that this can make it easier for you to write unit tests. The easier they are to write, the more likely developers will write them.
The entire source of this blog is accessible from Github at https://github.com/nbuesing/opiblog-premock and is a complete Eclipse project.
In a future article I will extend what I started here to write unit-test for GWT that does not need the GWTTestCase.