Mockito Mocking Final Classes and Methods

1. Overview

In Mockito 2 and later versions, the library comes with the capability to mock final classes and methods. This was a significant improvement as in earlier versions, mocking final classes and methods was not directly supported. In this tutorial, we'll walk through the process of mocking final classes and methods using Mockito.

2. Development Steps

1. Set up a new Maven project.

2. Add the necessary Mockito, JUnit 5, and Mockito-inline dependencies.

3. Create a final class named 'FinalClass' and a final method within to demonstrate mocking.

4. Design a test class showcasing the mocking of the final class and method.

5. Execute the tests to understand the outcomes.

6. Reflect on the advantages of being able to mock final classes and methods.

3. Dependencies (Mockito and JUnit 5)

<!-- JUnit 5 -->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>
<!-- Mockito Core -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>5.6.0</version>
    <scope>test</scope>
</dependency>
<!-- Mockito-inline for mocking final classes -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-inline</artifactId>
    <version>5.6.0</version>
    <scope>test</scope>
</dependency>

4. Code Program

// Step 3: Define the FinalClass with a final method
final class FinalClass {
    final String finalMethod() {
        return "Original Output from final method";
    }
}
// Step 4: Create the test class for FinalClass
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
public class FinalClassTest {
    @Test
    public void testMockingFinalMethod() {
        // Mocking the FinalClass
        FinalClass mockFinalClass = mock(FinalClass.class);
        // Mocking the behavior of the final method
        when(mockFinalClass.finalMethod()).thenReturn("Mocked Output");
        // Using the mock object
        String result = mockFinalClass.finalMethod();
        System.out.println(result);
        // Verifying the mocked method was called
        verify(mockFinalClass, times(1)).finalMethod();
    }
}

Output:

Mocked Output

Code Explanation:

1. We've defined a FinalClass with a finalMethod. Typically, this setup would mean we cannot override the behavior of finalMethod.

2. In the test class, FinalClass is successfully mocked using Mockito, even though it's a final class.

3. We then mock the behavior of the finalMethod to return a different string than its original implementation.

4. Upon invoking the mocked method, it's evident that the original implementation is bypassed, and the mocked behavior is executed.

5. The verify() method confirms our mocked method was called the expected number of times.

5. Conclusion

Mockito's ability to mock final classes and methods offers greater flexibility and power to testers and developers. Before this feature, developers often had to redesign their classes to make them more testable, or use other workarounds. Now, with straightforward configurations and the mockito-inline dependency, Mockito ensures that final classes and methods are no longer a hurdle in achieving comprehensive test coverage.

Comments