Skip to content

Add first-class support for mocking object singletons#587

Merged
jselbo merged 2 commits intomockito:mainfrom
jselbo:mock-object-singletons
Mar 19, 2026
Merged

Add first-class support for mocking object singletons#587
jselbo merged 2 commits intomockito:mainfrom
jselbo:mock-object-singletons

Conversation

@jselbo
Copy link
Copy Markdown
Contributor

@jselbo jselbo commented Mar 11, 2026

Fixes: #536

This builds off the new mockSingleton feature of Mockito-core which enables thread-local intercepting instance methods of existing objects. This was added to enable mocking Kotlin object and companion object singletons. See mockito/mockito#3762

Very excited to finally add this feature!

This is comparable to MockK's mockkObject.


// This will compile to a static method callable by both Java and Kotlin.
// It must be mocked and stubbed with mockStatic!
@JvmStatic fun helloStatic(): String = "static_unstubbed"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only gotcha - @JvmStatic marked methods in object (but not companion object) compile only to a static method and must be mocked with mockStatic.

I plan to update the wiki page with more info about mocking objects after this is merged!

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang, this is super tricky!
I wonder if we could signal this somehow to people.

I know this is also what libs like MockK do, but if we could surface that somehow, then it could help Mockito stand out. That'd be a whole new discussion though, outside this PR.

My random idea

What if Mockito had a lint lib that people could easily pull and use?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint is an interesting idea, though it would be hard to get traction. I'd prefer a built-in solution.

I also hate that this gotcha exists. We could try to be smart and invoke mockStatic under the hood if we detect @JvmStatic methods. Let me explore this option.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! I LOVED your solution! Really clever, ship it! 🚀

implementation "org.jetbrains.kotlin:kotlin-reflect:2.1.20"

api "org.mockito:mockito-core:5.20.0"
api "org.mockito:mockito-core:5.23.0"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, wow! I'm surprised this is not extracted to a param somewhere so we'd have a single source of truth for the version across the mockito libs.
Interesting to know, but certainly not something related to this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only place we specify the mockito-core version in this repo. But there duplicated versions across the build.gradle files. As I follow-up I can convert this to use Gradle version catalog

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit naturally grown and should certainly be fixed.


// This will compile to a static method callable by both Java and Kotlin.
// It must be mocked and stubbed with mockStatic!
@JvmStatic fun helloStatic(): String = "static_unstubbed"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang, this is super tricky!
I wonder if we could signal this somehow to people.

I know this is also what libs like MockK do, but if we could surface that somehow, then it could help Mockito stand out. That'd be a whole new discussion though, outside this PR.

My random idea

What if Mockito had a lint lib that people could easily pull and use?

…nd wrapping the closeables in a MockedObject type

// This will compile to a static method callable by both Java and Kotlin.
// It must be mocked and stubbed with mockStatic!
@JvmStatic fun helloStatic(): String = "static_unstubbed"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow! I LOVED your solution! Really clever, ship it! 🚀

Copy link
Copy Markdown
Member

@raphw raphw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, too. Clean and well-documented.

@jselbo jselbo merged commit ce67cbd into mockito:main Mar 19, 2026
3 checks passed
@jselbo jselbo deleted the mock-object-singletons branch March 19, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

How to properly mock companion object methods?

3 participants