<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/medium-zbjb7tuf9" -->

---
title: Medium | daily.dev
description: A deep dive into Mockito covering its internal architecture, ByteBuddy-based bytecode generation, the MockMaker SPI, and how stubbing and verification actually...
canonical: https://daily.dev/posts/medium-zbjb7tuf9
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: Medium | daily.dev
og:description: A deep dive into Mockito covering its internal architecture, ByteBuddy-based bytecode generation, the MockMaker SPI, and how stubbing and verification actually...
og:url: https://daily.dev/posts/medium-zbjb7tuf9
og:image: https://api.daily.dev/og/posts/ZbJb7tuf9.png
og:image:alt: Medium
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Medium

**[Medium](https://daily.dev/sources/medium_js)** · 21 min read · 0 upvotes · 0 comments

## Summary

A deep dive into Mockito covering its internal architecture, ByteBuddy-based bytecode generation, the MockMaker SPI, and how stubbing and verification actually work under the hood. Covers every mock creation approach (@Mock, @InjectMocks, parameter injection), all stubbing styles (when/thenReturn, doReturn/when, BDDMockito), argument matchers and their mixing rules, verification patterns including InOrder and ArgumentCaptor, spy semantics and why doReturn is safer on spies, static/final/constructor mocking with mockito-inline, common exceptions and their root causes, Spring Boot integration with @MockitoBean/@MockitoSpyBean, and anti-patterns to avoid.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://deepawasthi.medium.com/java-mockito-68dfedea440a>

## Questions this post answers

### Why can't Mockito mock a final class or a static method by default, and how do I fix it?

By default Mockito's MockMaker generates mocks by subclassing the target type, so it cannot override final classes, final methods, or static methods since none of those can be subclassed. Adding the mockito-inline artifact swaps in a MockMaker that rewrites bytecode directly via java.lang.instrument, enabling mocking of final classes, final methods, static methods, and even constructors. Starting with Mockito 5, inline mocking became the default.

_Developers wrestling with unmockable final classes can track Mockito version changes like this on daily.dev._

### Why does Mockito throw UnnecessaryStubbingException even though my test passes?

UnnecessaryStubbingException happens because the JUnit 5 native MockitoExtension defaults to strict stubbing since Mockito 2, which tracks whether every configured stub actually gets invoked during the test. If a stub like when(repository.findById(1L)).thenReturn(order) is never called with that exact argument, the test fails at the end of the run instead of leaving dead setup code behind. Fix it by removing the unused stub or marking it lenient with lenient().when(...) or @MockitoSettings(strictness = Strictness.LENIENT).

_Anyone debugging strict stubbing failures can keep testing best practices like these close on daily.dev._

### Why does when(spy.someMethod()).thenReturn(...) behave unexpectedly on a Mockito spy?

Calling when() on a spy actually executes the real method first, since a spy delegates to real behavior by default, before Mockito attaches the stub. If that real method has side effects, throws under current test conditions, or is expensive, when-first stubbing can break in surprising ways. Using doReturn(value).when(spy).someMethod() avoids invoking the real method during stubbing, making it the safer choice for spies.

_Developers choosing between mocks and spies can weigh trade-offs like this while browsing testing content on daily.dev._

## Similar posts on daily.dev

- [What is @MockitoSpyBean in Spring](https://daily.dev/posts/what-is-mockitospybean-in-spring-aaolrau6n) · Baeldung · 3 upvotes · 0 comments
- [Testing the untestable](https://daily.dev/posts/testing-the-untestable-lw2nlebp0) · A Java geek · 0 upvotes · 0 comments
- [Unit Testing with Dependency Injection in KMP Using Mokkery](https://daily.dev/posts/unit-testing-with-dependency-injection-in-kmp-using-mokkery-3k0nyncka) · ITNEXT · 0 upvotes · 0 comments
- [Mockito Argument Matchers: any\(\), eq\(\) and More](https://daily.dev/posts/mockito-argument-matchers-any-eq-and-more-cbc5b7kdn) · DigitalOcean Community · 3 upvotes · 0 comments

---

Tags: [#testing](https://daily.dev/tags/testing), [#java](https://daily.dev/tags/java), [#spring-boot](https://daily.dev/tags/spring-boot)

[View this post on daily.dev](https://daily.dev/posts/medium-zbjb7tuf9)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"Medium","url":"https://daily.dev/posts/medium-zbjb7tuf9","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/medium-zbjb7tuf9"},"datePublished":"2026-07-22T04:40:14.558Z","dateModified":"2026-09-14T09:28:25.339Z","description":"A deep dive into Mockito covering its internal architecture, ByteBuddy-based bytecode generation, the MockMaker SPI, and how stubbing and verification actually...","image":"https://media.daily.dev/image/upload/s--HRgLpUt6--/f_auto/v1722860399/public/Placeholder%2003","thumbnailUrl":"https://media.daily.dev/image/upload/s--HRgLpUt6--/f_auto/v1722860399/public/Placeholder%2003","isAccessibleForFree":true,"articleSection":"Medium","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Medium","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/medium","url":"https://daily.dev/sources/medium_js"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/medium-zbjb7tuf9","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"testing,java,spring-boot","timeRequired":"PT21M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Medium","item":"https://daily.dev/sources/medium_js"},{"@type":"ListItem","position":3,"name":"Medium"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/medium-zbjb7tuf9#faq","mainEntity":[{"@type":"Question","name":"Why can't Mockito mock a final class or a static method by default, and how do I fix it?","acceptedAnswer":{"@type":"Answer","text":"By default Mockito's MockMaker generates mocks by subclassing the target type, so it cannot override final classes, final methods, or static methods since none of those can be subclassed. Adding the mockito-inline artifact swaps in a MockMaker that rewrites bytecode directly via java.lang.instrument, enabling mocking of final classes, final methods, static methods, and even constructors. Starting with Mockito 5, inline mocking became the default. Developers wrestling with unmockable final classes can track Mockito version changes like this on daily.dev."}},{"@type":"Question","name":"Why does Mockito throw UnnecessaryStubbingException even though my test passes?","acceptedAnswer":{"@type":"Answer","text":"UnnecessaryStubbingException happens because the JUnit 5 native MockitoExtension defaults to strict stubbing since Mockito 2, which tracks whether every configured stub actually gets invoked during the test. If a stub like when(repository.findById(1L)).thenReturn(order) is never called with that exact argument, the test fails at the end of the run instead of leaving dead setup code behind. Fix it by removing the unused stub or marking it lenient with lenient().when(...) or @MockitoSettings(strictness = Strictness.LENIENT). Anyone debugging strict stubbing failures can keep testing best practices like these close on daily.dev."}},{"@type":"Question","name":"Why does when(spy.someMethod()).thenReturn(...) behave unexpectedly on a Mockito spy?","acceptedAnswer":{"@type":"Answer","text":"Calling when() on a spy actually executes the real method first, since a spy delegates to real behavior by default, before Mockito attaches the stub. If that real method has side effects, throws under current test conditions, or is expensive, when-first stubbing can break in surprising ways. Using doReturn(value).when(spy).someMethod() avoids invoking the real method during stubbing, making it the safer choice for spies. Developers choosing between mocks and spies can weigh trade-offs like this while browsing testing content on daily.dev."}}]}
```

