Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 2–5 Years

Revise the Fresher Tier

  • Revise: Core Java Fundamentals (Fresher Tier)
  • Revise: Collections, Threads, Java 8 & Coding (Fresher Tier)
  • Revise: Spring Core, Spring Boot & Spring MVC (Fresher Tier)
  • Revise: Hibernate, SQL, Microservices, Maven & Git (Fresher Tier)

Intermediate Core Java

  • Intermediate OOP & Language Features — Interview Questions
  • Enums, Generics, Pass-by-Value & Imports — Interview Questions
  • Collections Internals & Scenarios — Interview Questions
  • JVM, Memory & Class Loading — Interview Questions
  • Exception Design & Serialization Edge Cases — Interview Questions

Java 8 Deep Dive & Stream Coding

  • Lambdas, Functional Interfaces & Method References — Interview Questions
  • Default Methods, Backward Compatibility & Optional — Interview Questions
  • Stream API Internals (Part 1) — Interview Questions
  • Stream API Internals (Part 2) — Interview Questions
  • Stream Coding Problems (Level 2, Part 1) — Interview Questions
  • Stream Coding Problems (Level 2, Part 2) — Interview Questions

Concurrency & Multithreading

  • Synchronization, Locks & Deadlocks — Interview Questions
  • Executors, ThreadLocal & Concurrent Collections — Interview Questions

Spring Framework In Depth

  • Bean Lifecycle, Contexts & Circular Dependencies — Interview Questions
  • Spring Bean Conflicts, AOP, Batch & Injection Styles — Interview Questions

Spring Boot In Depth & Scenarios

  • Spring Boot Internals & Auto-Configuration — Interview Questions
  • Spring Boot Configuration, Profiles & Secrets — Interview Questions
  • Spring Boot Data, Transactions & Caching — Interview Questions
  • Spring Boot Testing, Error Pages & Deployment — Interview Questions
  • Spring Boot Performance, Scaling & Resilience — Interview Questions
  • Spring Boot Async, Events & Messaging — Interview Questions
  • Spring Boot Security Scenarios — Interview Questions
  • Actuator, AOP, Spring Cloud & Distributed Tracing — Interview Questions
  • External APIs, Files, GraphQL & WebFlux — Interview Questions

Spring Security

  • Spring Security — OAuth2, CORS, CSRF & Access Rules — Interview Questions
  • Spring Security — Passwords, Filter Chain, Sessions & Debugging — Interview Questions

Apache Kafka

  • Kafka Architecture, Topics & ZooKeeper vs KRaft — Interview Questions
  • Kafka Producers, Consumers, Reliability & Streams — Interview Questions
  • Kafka Security, Connect & Core Scenarios — Interview Questions
  • Kafka Production Scenarios — Interview Questions

Git, Maven & Gradle (Level II)

  • Git Workflows, Rebase & Conflict Handling — Interview Questions
  • Git Recovery, Hooks, Tags & Collaboration — Interview Questions
  • Maven Builds, Multi-Module Projects & Dependency Resolution — Interview Questions
  • Maven Profiles, settings.xml, Plugins & Quality Gates — Interview Questions
  • Gradle Fundamentals, Migration & Dependencies — Interview Questions
  • Gradle Performance, Plugins, Testing & Publishing — Interview Questions

Deployment & CI/CD

  • Sessions, CI/CD Pipelines, Rollbacks & Secrets — Interview Questions
  • Migrations, Zero-Downtime Releases, Containers & Monitoring — Interview Questions

JUnit 5 & Mockito

  • JUnit 5 — Interview Questions
  • Mockito Basics — Interview Questions
  • Mockito Advanced & Tricky Questions — Interview Questions
Chaturmind
← Java Interview Prep: 2–5 Years

Revise the Fresher Tier

  • Revise: Core Java Fundamentals (Fresher Tier)
  • Revise: Collections, Threads, Java 8 & Coding (Fresher Tier)
  • Revise: Spring Core, Spring Boot & Spring MVC (Fresher Tier)
  • Revise: Hibernate, SQL, Microservices, Maven & Git (Fresher Tier)

Intermediate Core Java

  • Intermediate OOP & Language Features — Interview Questions
  • Enums, Generics, Pass-by-Value & Imports — Interview Questions
  • Collections Internals & Scenarios — Interview Questions
  • JVM, Memory & Class Loading — Interview Questions
  • Exception Design & Serialization Edge Cases — Interview Questions

Java 8 Deep Dive & Stream Coding

  • Lambdas, Functional Interfaces & Method References — Interview Questions
  • Default Methods, Backward Compatibility & Optional — Interview Questions
  • Stream API Internals (Part 1) — Interview Questions
  • Stream API Internals (Part 2) — Interview Questions
  • Stream Coding Problems (Level 2, Part 1) — Interview Questions
  • Stream Coding Problems (Level 2, Part 2) — Interview Questions

Concurrency & Multithreading

  • Synchronization, Locks & Deadlocks — Interview Questions
  • Executors, ThreadLocal & Concurrent Collections — Interview Questions

Spring Framework In Depth

  • Bean Lifecycle, Contexts & Circular Dependencies — Interview Questions
  • Spring Bean Conflicts, AOP, Batch & Injection Styles — Interview Questions

Spring Boot In Depth & Scenarios

  • Spring Boot Internals & Auto-Configuration — Interview Questions
  • Spring Boot Configuration, Profiles & Secrets — Interview Questions
  • Spring Boot Data, Transactions & Caching — Interview Questions
  • Spring Boot Testing, Error Pages & Deployment — Interview Questions
  • Spring Boot Performance, Scaling & Resilience — Interview Questions
  • Spring Boot Async, Events & Messaging — Interview Questions
  • Spring Boot Security Scenarios — Interview Questions
  • Actuator, AOP, Spring Cloud & Distributed Tracing — Interview Questions
  • External APIs, Files, GraphQL & WebFlux — Interview Questions

Spring Security

  • Spring Security — OAuth2, CORS, CSRF & Access Rules — Interview Questions
  • Spring Security — Passwords, Filter Chain, Sessions & Debugging — Interview Questions

Apache Kafka

  • Kafka Architecture, Topics & ZooKeeper vs KRaft — Interview Questions
  • Kafka Producers, Consumers, Reliability & Streams — Interview Questions
  • Kafka Security, Connect & Core Scenarios — Interview Questions
  • Kafka Production Scenarios — Interview Questions

Git, Maven & Gradle (Level II)

  • Git Workflows, Rebase & Conflict Handling — Interview Questions
  • Git Recovery, Hooks, Tags & Collaboration — Interview Questions
  • Maven Builds, Multi-Module Projects & Dependency Resolution — Interview Questions
  • Maven Profiles, settings.xml, Plugins & Quality Gates — Interview Questions
  • Gradle Fundamentals, Migration & Dependencies — Interview Questions
  • Gradle Performance, Plugins, Testing & Publishing — Interview Questions

Deployment & CI/CD

  • Sessions, CI/CD Pipelines, Rollbacks & Secrets — Interview Questions
  • Migrations, Zero-Downtime Releases, Containers & Monitoring — Interview Questions

JUnit 5 & Mockito

  • JUnit 5 — Interview Questions
  • Mockito Basics — Interview Questions
  • Mockito Advanced & Tricky Questions — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 2–5 YearsJUnit 5 & Mockito
✓ FreeIntermediate· 7 min read

Mockito Advanced & Tricky Questions — Interview Questions

Mocking static methods, verify vs verifyNoMoreInteractions, mocking final classes (inline mock maker is the default in Mockito 5), mocking parameters, method chains, stubs vs mocks, constructor injection, RETURNS_DEEP_STUBS and why to avoid it, taming randomness, and combining JUnit with Mockito well.

Published September 25, 2026


How to use this lesson

The "tricky" Mockito questions test whether you know when a mocking trick is a design smell. Answer with the mechanism, then say what you'd prefer. Static mocking, deep stubs and randomness are usually better solved by injecting a dependency.

Q1. How do you mock static methods with Mockito?

Short answer: Use Mockito.mockStatic(Type.class) in a try-with-resources block. The mock applies only to the current thread, and only inside the block. Since Mockito 5, the inline mock maker is the default, so no extra mockito-inline dependency is needed (on Mockito 3.4–4.x it was).

@Test
void usesFixedUuid() {
    UUID fixed = UUID.fromString("00000000-0000-0000-0000-000000000001");
    try (MockedStatic<UUID> uuid = mockStatic(UUID.class)) {
        uuid.when(UUID::randomUUID).thenReturn(fixed);
        assertEquals(fixed.toString(), orderIds.next());
    }                                                  // the real static behaviour is restored here
}

Key points to cover:

  • Prefer to refactor by injecting the dependency (IdGenerator, Clock). Static mocking is a tool for legacy code you can't change yet.
  • Some JDK classes can't be mocked this way.

Q2. What's the difference between verify() and verifyNoMoreInteractions()?

Short answer: verify(mock).m() asserts that a specific interaction happened. verifyNoMoreInteractions(mock) asserts that there were no interactions left unverified on that mock. Every call must have been verified already. (verifyNoInteractions(mock) asserts that the mock was never touched at all.)

Key points to cover:

  • Use verifyNoMoreInteractions sparingly. It makes tests brittle, because harmless new calls (a new log or metrics call on the mock) break unrelated tests. Reserve it for cases where "nothing else happens" is the requirement, for example "no further payment calls after a decline".

Q3. How do you mock final classes and methods? Was it possible in older Mockito?

Short answer: Mockito 2.1 introduced the inline mock maker (opt-in, through mock-maker-inline or the mockito-inline artifact), which uses a Java agent and instrumentation to mock final classes and methods. Since Mockito 5, the inline mock maker is the default, so mocking finals just works. Mockito 1.x couldn't do it at all: it subclassed via CGLIB, and final types can't be subclassed. PowerMock was the workaround back then, and it's effectively dead now.

Key points to cover:

  • Kotlin classes are final by default, which is one reason the inline maker became the default.
  • Mocking final value types or records is still usually a smell. Construct real ones.

Q4. How do you mock dependencies that are passed to a method as parameters?

Short answer: Create the mock yourself, and pass it in as the argument. No injection magic is needed. Stub it, call the method, then verify.

@Test
void notifiesEveryListener() {
    OrderListener a = mock(OrderListener.class), b = mock(OrderListener.class);
    publisher.publish(order, List.of(a, b));
    verify(a).onOrder(order);
    verify(b).onOrder(order);
}

Key points to cover:

  • If the parameter is a simple value or data object, use a real instance. Mock only behavioural collaborators.

Q5. How do you handle method chaining, such as foo.bar().baz()?

Short answer: Stub each link, returning a mock for the intermediate objects. Or use RETURNS_DEEP_STUBS (see Q8). But mocking long chains is a strong sign of a Law of Demeter violation: the code under test knows too much about object internals.

when(customer.getAccount()).thenReturn(account);
when(account.getTier()).thenReturn(Tier.GOLD);
// better design: customer.tier(), or pass the Tier in directly

Key points to cover:

  • Fluent builders (like RestClient, or JPA Criteria) are the one common exception, and there it's usually better to test against a real HTTP stub (WireMock) or database than to mock the chain.

Q6. What's the difference between a stub and a mock?

Short answer: Both are test doubles:

  • A stub provides canned answers, so the code under test can run. You assert on the result or state of the system under test.
  • A mock is used to verify interactions: which calls happened, with what arguments, how many times. The test fails if the expected interaction didn't happen.

Other doubles: fakes (working lightweight implementations, such as an in-memory repository), spies (real objects that record calls) and dummies (placeholders).

Key points to cover:

  • In Mockito, the same mock() object can act as either. The distinction is how you use it: when (stubbing) vs verify (mocking).

Q7. How do you mock objects when the class under test uses constructor injection?

Short answer: Create the mocks, and pass them to the constructor directly. That's the simplest and most explicit option, and the compiler flags missing dependencies. @InjectMocks also picks the largest constructor, but it fails more quietly.

@ExtendWith(MockitoExtension.class)
class CheckoutServiceTest {
    @Mock PaymentGateway gateway;
    @Mock OrderRepository orders;
    CheckoutService checkout;

    @BeforeEach void setUp() { checkout = new CheckoutService(gateway, orders, Clock.fixed(NOW, UTC)); }
}

Q8. What is RETURNS_DEEP_STUBS, and when would you use it?

Short answer: mock(Type.class, RETURNS_DEEP_STUBS) makes every method in a chain automatically return another mock, so when(a.b().c().d()).thenReturn(x) works without stubbing each level.

When: rarely. It's for quickly wrapping fluent APIs you don't control in legacy tests.

Why to avoid it: it hides design problems (deep coupling), produces confusing failures, and doesn't work with generic or final return types in some cases. Mockito's own documentation calls it a code smell. Prefer small interfaces, or real in-memory implementations.

Q9. How do you control behaviour that depends on randomness, such as Math.random()?

Short answer: Make the randomness a dependency. Inject a RandomGenerator (Java 17's interface), a Random with a fixed seed, or your own IdGenerator/Dice interface. Then tests pass a deterministic implementation, or a mock.

class CouponService {
    private final RandomGenerator random;
    CouponService(RandomGenerator random) { this.random = random; }
    String code() { return "SAVE" + random.nextInt(1000, 10000); }
}
// production: new CouponService(new SecureRandom())
// test:       new CouponService(new Random(42))                    → a predictable sequence
// or mock:    when(random.nextInt(1000, 10000)).thenReturn(4321)

Key points to cover:

  • The same principle applies to time (inject a Clock), UUIDs and environment variables. Anything non-deterministic belongs behind an injected seam.

Q10. How do you combine JUnit and Mockito to write comprehensive unit tests?

Short answer: JUnit 5 provides the structure (lifecycle, parameterized tests, assertions, nested scenarios), and Mockito provides the isolation (stubbing collaborators, verifying the important interactions). A comprehensive test class covers:

  • the happy path;
  • boundary values (parameterized);
  • each failure mode of each collaborator (thenThrow);
  • what must not happen (never());
  • what was passed to side-effecting collaborators (captors).
@ExtendWith(MockitoExtension.class)
class RefundServiceTest {
    @Mock PaymentGateway gateway;
    @Mock RefundRepository refunds;
    @InjectMocks RefundService service;

    @Nested class WhenPaymentWasCaptured {
        @Test void refundsAndRecords() {
            when(gateway.refund("ch_1", MONEY_100)).thenReturn(RefundResult.ok("re_1"));
            service.refund(capturedPayment("ch_1", MONEY_100));
            verify(refunds).save(argThat(r -> r.gatewayRef().equals("re_1")));
        }
        @Test void recordsFailureWithoutCrashing() {
            when(gateway.refund(any(), any())).thenThrow(new GatewayTimeoutException());
            assertThrows(RefundPendingException.class, () -> service.refund(capturedPayment("ch_1", MONEY_100)));
            verify(refunds).save(argThat(r -> r.status() == RefundStatus.PENDING_RETRY));
        }
    }
    @ParameterizedTest @ValueSource(strings = { "0", "-1" })
    void rejectsNonPositiveAmounts(String amount) {
        assertThrows(IllegalArgumentException.class, () -> service.refund(capturedPayment("ch_1", new BigDecimal(amount))));
        verifyNoInteractions(gateway);
    }
}

Key points to cover:

  • Complement the unit tests with a few integration tests (Spring slices with Testcontainers), so mocked assumptions are checked against reality.

Follow-up questions this topic invites — and their answers

Q: What is BDDMockito? A: An alias API matching Given–When–Then style: given(repo.findById(1L)).willReturn(Optional.of(o)) and then(mailer).should().send(any()). Same behaviour, different vocabulary.

Q: How do you test code that runs asynchronously with mocks? A: Use verify(mock, timeout(1000)).method(), or Awaitility for state checks. Better still, inject an executor that runs tasks synchronously in unit tests.

Q: Why can over-mocking make a test suite worthless? A: When every collaborator is mocked, and every interaction verified, tests mirror the implementation. They break on every refactor, and still pass when the real collaborators behave differently. Mock only at the boundaries, and test behaviour.

Q: How do you mock a generic type without unchecked warnings? A: Use @Mock fields (Mockito infers the generics), or mock(Repository.class) with @SuppressWarnings("unchecked") on a narrowly scoped variable.

Previous

Mockito Basics — Interview Questions

AI Tutor

Lesson: Mockito Advanced & Tricky Questions — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.