Fixing Quarkus gRPC: Overcome Mockito's Final Class Limitation
Fixing Quarkus gRPC: Overcome Mockito's Final Class Limitation

Fixing Mockito Cannot Mock Final Class Error in Java Quarkus gRPC

Encountering "Cannot mock final class" in Quarkus gRPC Java tests? Learn Mockito limits and how to effectively fix them.6 min


You’re working on your Java application using Quarkus gRPC, and suddenly, when writing tests with Mockito, you encounter this frustrating error: “Cannot mock final class”. This error message seems cryptic at first, but it makes sense once you understand Mockito’s limitations. Let’s explore why this error happens and how you can effectively fix it.

Why Mockito Complains About Final Classes

Before fixing the issue, let’s understand what’s happening. Mockito is a popular mocking library for unit testing Java applications. It allows developers to mock interactions, behaviors, and dependencies of certain objects.

However, Mockito struggles with final classes. You see, when Java classes are declared with the keyword “final“, they can’t be subclassed or extended. Mockito internally creates dynamic subclasses behind the scenes to provide mocks—but when it encounters a final class, it simply can’t.

The reason for this limitation is straightforward: Java’s rules forbid subclassing final classes, and standard Mockito mocks rely on subclassing to intercept method calls and provide mocked responses.

Your Classes at Play: Java Quarkus and gRPC Context

When using Quarkus and gRPC, you often generate service stubs and message classes automatically using the proto definitions. These gRPC-generated classes are frequently marked as final classes, making them tricky to mock while testing.

You might have a scenario like this:

final class GreetingServiceGrpc {
    static final class GreetingServiceImplBase extends BindableService {
        // Generated service implementation class
    }
}

Testing components that depend on these auto-generated classes leads to Mockito stumbling upon their final nature.

How Do You Fix This?

Often, there are two reliable approaches you can take:

  1. Use a more powerful mocking library that supports mocking final classes—like PowerMock with Mockito.
  2. Refactor your code to avoid direct dependencies on final classes, thus simplifying testing altogether.

Let’s dive straight into these options clearly so you understand their strengths and pitfalls.

Option 1: Using PowerMock with Mockito

PowerMock extends Mockito capabilities significantly, allowing you to mock static methods, private methods, and importantly, final classes.

Here’s how to set it up:

  1. Add the PowerMock dependencies to your project (usually through Maven or Gradle).
  2. Update your test cases to use the PowerMock runner.
  3. Mock the final class successfully.

First, include the dependencies like this (Maven example):

<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-module-junit4</artifactId>
  <version>2.0.9</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.powermock</groupId>
  <artifactId>powermock-api-mockito2</artifactId>
  <version>2.0.9</version>
  <scope>test</scope>
</dependency>

For Gradle users, it looks like this:

testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'

Now adjust your test class:

@RunWith(PowerMockRunner.class)
@PrepareForTest({GreetingServiceGrpc.GreetingServiceImplBase.class})
public class GreetingServiceTest {

    @Test
    public void testGreetingService() {
        GreetingServiceGrpc.GreetingServiceImplBase mockService = 
          PowerMockito.mock(GreetingServiceGrpc.GreetingServiceImplBase.class);

        // Define behavior
        Mockito.when(mockService.someMethod()).thenReturn(yourMockResponse);

        // Proceed with your tests
    }
}

With PowerMock integrated, your tests involving mocks of final classes should now run smoothly.

Option 2: Change Your Design Instead

The second approach might sound more daunting initially but often results in cleaner, simpler, and more maintainable code overall.

Instead of relying heavily on mocking final classes, restructure your app to abstract these dependencies using interfaces or wrapper classes. Let’s see how you might achieve this conveniently in Quarkus gRPC:

  1. Create an interface wrapping operations you perform on the generated gRPC service class.
  2. Implement this interface in a concrete wrapper class.
  3. Set dependencies to rely on the interface rather than the auto-generated final class.

For example, your existing dependency on the final GreetingServiceGrpc class might change from:

public class MyService {
    private final GreetingServiceGrpc.GreetingServiceImplBase greetingService;

    public MyService(GreetingServiceGrpc.GreetingServiceImplBase service) {
        this.greetingService = service;
    }
}

To something more test-friendly like:

// Interface
public interface GreetingsHandler {
  YourResponseType someMethod();
}

// Implementation
public class GreetingWrapper implements GreetingsHandler {
    private final GreetingServiceGrpc.GreetingServiceImplBase service;

    public GreetingWrapper(GreetingServiceGrpc.GreetingServiceImplBase service) {
        this.service = service;
    }

    @Override
    public YourResponseType someMethod() {
        return service.someMethod();
    }
}

// Refactored Dependency Usage
public class MyService {
    private final GreetingsHandler greetingsHandler;

    public MyService(GreetingsHandler greetingsHandler) {
        this.greetingsHandler = greetingsHandler;
    }
}

This approach allows your tests to mock your interface effortlessly without facing any Mockito limitations:

@Test
public void testMyService() {
    GreetingsHandler mockHandler = Mockito.mock(GreetingsHandler.class);
    MyService myService = new MyService(mockHandler);

    Mockito.when(mockHandler.someMethod()).thenReturn(dummyResponse);

    YourResponseType result = myService.callGreeting();

    Assert.assertEquals(dummyResponse, result);
}

Pros and Cons of Both Options

Here’s how both methods stack up practically:

Approach Pros Cons
PowerMock + Mockito Quick fix; no major design changes needed Potentially brittle tests; extra complexity in tests
Design Refactoring More maintainable and cleaner solution; improves code quality Initial extra effort to refactor existing implementations

The recommended approach is usually design refactoring, as it yields more maintainable and clean code in your application ecosystem, despite some upfront work.

Best practices for Quarkus gRPC Testing

Adopting the following best practices helps keep testing smooth:

  • Prefer designing components with clear interfaces for easy mocking.
  • Use Mockito for simple mocking whenever possible.
  • Isolate generated or third-party final classes behind wrapper classes or interfaces.
  • Consider libraries like PowerMock only if necessary—keep tests simple.

By making informed design patterns your practice, you significantly improve code maintainability and reduce future headaches.

When you encounter similar issues next time, remember: understanding the root cause of Mockito’s limitations helps easily pick between adjusting your libraries or tweaking your design. Which option did you choose—or do you prefer a different approach altogether? Feel free to share your experience!


Like it? Share with your friends!

Shivateja Keerthi
Hey there! I'm Shivateja Keerthi, a full-stack developer who loves diving deep into code, fixing tricky bugs, and figuring out why things break. I mainly work with JavaScript and Python, and I enjoy sharing everything I learn - especially about debugging, troubleshooting errors, and making development smoother. If you've ever struggled with weird bugs or just want to get better at coding, you're in the right place. Through my blog, I share tips, solutions, and insights to help you code smarter and debug faster. Let’s make coding less frustrating and more fun! My LinkedIn Follow Me on X

0 Comments

Your email address will not be published. Required fields are marked *