Mockito is a widely used Java mocking framework. It has evolved over the years to offer an array of features that simplify the testing process and ensure the reliability of software applications. One notable improvement is the ability to mock methods of local scope objects, eliminating the need for PowerMock in the latest Mockito versions coupled with JUnit 5.

In this article, we’ll explore a technique to mock both new instance creation and static methods using Mockito’s mockConstruction() and mockStatic() methods. We’ll dive into a practical example to demonstrate their usage and highlight their benefits.

Mocking local scope objects

In scenarios where we need to mock methods of objects created within the method scope, traditional mocking techniques can fall short.

This is particularly relevant when dealing with new instance creations or static methods.

Mockito, in combination with JUnit 5, offers a solution to this challenge, providing a more streamlined approach to local scope object mocking.

Mockito’s mockConstruction() and mockStatic()

The mockConstruction() method enables the mocking of new instance creations. Similarly, the mockStatic() method is used for mocking static methods.

Both these methods bring the power of Mockito to local scope object mocking.

Practical example: Local scope object mocking

Let’s consider a scenario where we want to mock methods of a local scope object, PdfConverter, within a particular method, convert(). This method internally creates an instance of ITextRenderer and calls methods like setDocumentFromString(), layout() and createPDF() to generate a PDF document.

Here’s how you can mock locally created object using mockConstruction():

class PdfConverterTest {
    private PdfConverter converter;

    @BeforeEach
    void setup() {
        converter = new PdfConverter();
    }

    @Test
    void shouldThrowExceptionWhenXhtmlCanNotBeConverted() throws IOException {
        try (MockedConstruction<ITextRenderer> ignored = Mockito.mockConstruction(ITextRenderer.class,
            (mock, context) -> {
                // setup methods on mock
                doNothing().when(mock).setDocumentFromString(any()); 
                doNothing().when(mock).layout();
                doThrow(new DocumentException())
                    .when(mock)
                    .createPDF(any());
            })) {
            assertThrows(IOException.class, () -> converter.convertXhtmlToPdf("<xhtml><body><h1>Hey there</h1></body></xhtml>"));
        }
    }
}
Code language: Java (java)

In this example, we’re creating a mocked instance of ITextRenderer.

We are specifying the behaviour of its methods using doNothing() and doThrow() from the Mockito framework. These are especially useful for methods with a return type of void.

Can’t we use dependency injection?

Let’s face it, dependency injection is a much better solution that can avoid the need to mock locally created objects. However, there are situations where it might not be the pragmatic solution.

Legacy codebases, complex initialization logic, and concerns about thread safety often prompt the use of local scope object mocking.

Legacy systems might not easily accommodate dependency injection, while complex initialization processes can complicate object instantiation. Additionally, in multi-threaded environments, local scope mocking can be the only way to unit test a dependency.

Despite dependency injection’s value, local scope object mocking provides isolated testing, helping developers strike a balance between best practices and practicality when addressing testing challenges.

Conclusion

Mocking methods of local scope objects is an essential aspect of unit testing, ensuring the reliability and accuracy of your software applications.

With the introduction of Mockito’s mockConstruction() and mockStatic() methods, the process of mocking new instance creations and static methods has become more straightforward, eliminating the complexities associated with traditional approaches.

Umut Esen

Software Engineer specialising in full-stack web application development.

Leave a Reply

This Post Has One Comment

  1. Jocelynn H. Travis

    Your blog post was fantastic, thanks for the great content!