Wow, there's a lot of anger in some of these posts.
I've been using Mockito for about 4 years, all in Kotlin. I always found it to be "plenty good" for like 99% of the cases I needed it; and things more complicated or confusing or messy were usually my fault (poor separation of concerns, etc).
I regularly found it quite helpful in both its spy() and mock() functionality.
I never found it meaningfully more or less useful than MockK, though I have heard MockK is the "one that's better for Kotlin". It's mostly just vocabulary changes for me, the user.
I'm going to have to monitor Mockito's future and see if I'll need to swap to MockK at some point if Mockito becomes unmaintained.
Mock is effective when developers keep applications at 4-5 layers deep (and honestly, you don't need more than that 97% of the time: initiators, controllers, services, transports, and cross cutting concerns).
The problem is, engineers love to solve problems, and the funnest types of problems are hypothetical ones!
Yep, I was guiltily of taking DI and writing a spider web of code. It's not the tools fault, it was my attitude. I _wanted_ something hard to work on, so I created something hard to work on. Nowadays, my team and I work on a 4-5 layer deep limit and our code base is tight, consistent, and has near 99% test coverage naturally. We use mock testing for testing the single class, and of course integration test for testing requirements. Not everyone will do it this way, and that's fine, but the most important thing is actually just creating a plan and sticking to it so as to be consistent.
In the end, don't blame the tool, when you (or your coworkers) simply lack discipline.
For those, like me, who haven't heard of it: Mockito is the "most popular mocking framework for Java".
Running open source _anything_ looks exhausting from the outside.
I don't know why owners/maintainers show grace like this.
For me; I would say I'm done and hand it over or just archive the repo.
Hope Tim finds a measure of sanity after he steps down.
| My personal take is that folks involved with the change severely underestimated the societal impact that it had. The fact that proper build support is non-existent to this day shows that agents are not a priority. That's okay if it isn't a priority, but when it was communicated with Mockito I perceived it as "Mockito is holding the JVM ecosystem back by using dynamic attachment, please switch immediately and figure it out on your own".
Id like to hear the platform team's perspective on this. As it stands, it is a pretty sad state of affairs that such a prominent library in the ecosystem was made out to be the scapegoat for the adoption of a platform change. It is not a healthy thing to treat the library maintainer community like this.
>Mockito 5 shipped a breaking change where its main artifact is now an agent. That's because starting JVM 22, the previous so-called "dynamic attachment of agents" is put behind a flag
Wouldn't this hold back enterprise adoption, the same way breaking changes meant that Java 8 was widely used for a long time?
TimvdLippe: You've done an incredible job. You have incredible ideas and vision. Just wanted to say thank you.
Mockito is fine if you know how to write tests. You can write bad tests with Mockito or many other frameworks if that’s what you do. You can even write bad tests while programming in Rust from high up in your ivory tower. You can write good tests also.
What does Agent mean in this context? And what is "dynamic attachment of agents"?
IMO mockito has a relatively good use experience. If you use MockitoExtension, especially, you write code that is relatively maintainable, and easy to mutate. The problem without MockitoExtension is you can throw all kinds of junk in there and it just sits there doing nothing, without you knowing it.
Spy's on the other hand, are a pain in the neck. I think they should be good in theory, but in practice they are difficult, the debuggers really don't work correctly, setting breakpoints, stepping, etc, is just broken in many cases. Would love to know if this is just a difficult bug, or something that is baked into spying.
> That's because starting JVM 22, the previous so-called "dynamic attachment of agents" is put behind a flag.
Ok am I being stupid or is the pragmatic solution not to just to enable this flag for test runs etc. and leave it off in prod?
> To me, it felt like the feature was presented as a done deal because of security.
Not security, but integrity, although security (which is the #1 concern of companies relying on a platform responsible for trillions of dollars) is certainly one of the primary motivations for integrity (others being performance, backward compatibility or "evolvability", and correctness). Integrity is the ability of code to locally declare its reliance on some invariant - e.g. that a certain class must not be extended, that a method can only be called by other methods in the same class, or that a field cannot be reassigned after being assigned in the constructor - and have the platform guarantee that the invariant is preserved globally throughout the lifetime of the program, no matter what other code does. What we call "memory safety" is an example of some invariants that have integrity.
This is obviously important for security as it significantly reduces the blast radius of a vulnerability (some attacks that can be done in JS or Python cannot be done in Java), but it's also important for performance, as the compiler needs to know that certain optimisations preserve meaning. E.g. strings cannot be constant-folded if they can't be relied upon to be truly immutable. It's also important for backward-compatibility or "evolvability", as libraries cannot depend on internals that are not explicitly exposed as public APIs; libraries doing that was the cause of the migration pain from Java 8 to 9+, as lots of libraries depended on internal, non-API methods that have changed when the JDK's evolution started picking up steam.
In Java, we've adopted a policy we call Integrity by Default (https://openjdk.org/jeps/8305968), which means that code in one component can violate invariants established by code in another component only if the application is made aware of it and allows it. What isn't allowed is for a library - which could be some fourth-level dependency - to decide for itself at some point during the program's execution, without the application's knowledge, that actually strings in this program should be mutable. We were, and are, open to any ideas as long as this principle is preserved.
Authors of components that do want to do such things find the policy inconvenient because their consumers need to do something extra that isn't required when using normal libraries. But this is a classic case of different users having conflicting requirements. No matter what you do, someone will be inconvenienced. We, the maintainers of the JDK, have opted for a solution that we believe minimises the pain and risk overall, when integrated over all users: Integrity is on by default, and components that wish to break it need an explicit configuration option to allow that.
> built on a solid foundation with ByteBuddy
ByteBuddy's author acknowledges that at least some aspects of ByteBuddy - and in particular the self-loading agent that Mockito used - weren't really a solid foundation, but now it should be: https://youtu.be/AzfhxgkBL9s?t=1843. We are grateful to Rafael for explaining his needs to us so that we could find a way to satisfy them without violating Integrity by Default.
This is a good opportunity to ditch mocking and use fakes with adapters. Not only mocks create brittle tests that often test only the framework itself, but they do so in an order of magnitude slower way.
Also, F Kotlin and their approach of "we'll reinvent the wheel with slightly different syntax and call it a new thing". Good riddance I say, let them implement their mockk, or whatever it is called, with ridiculous "fluent" syntax.
I respect the maintainer's decision, but I don't understand the justification.
> but when it was communicated with Mockito I perceived it as "Mockito is holding the JVM ecosystem back by using dynamic attachment, please switch immediately and figure it out on your own".
Who did the communication? Why is dynamic attachment through a flag a problem, and what was the solution? Why is "enable a flag when running tests" not a satisfactory solution? Why do you even need a _dynamic_ agent; don't you know ahead of time exactly what agent you need when using Mockito?
> While I fully understand the reasons that developers enjoy the feature richness of Kotlin as a programming language, its underlying implementation has significant downsides for projects like Mockito. Quite frankly, it's not fun to deal with.
Why support Kotlin in the first place? If it's a pain to deal with, perhaps the Kotlin user base is better served by a Kotlin-specific mocking framework, maintained by people who enjoy working on those Kotlin-specific code paths?
As someone who is not in the Java world, why does Java need a mocking library? Interface based polymorphism is not enough?
Sad to see an important project's core maintainer leave but their justification seems very understandable. It is sad so much of OSS is maintained by very few as they alluded to in the XKCD comment, an especially given they felt the JVM ecosystem was causing them pain with limited support or feedback possible. I think it is always a little irresponsible to cause a great deal of breakage and not be there to support those who you break downstream of your project.
An excellent stepping down post, nothing more could be hoped for. Enjoy the next projects
Beware of a supply chain attack
A lot of OSS burnout comes from a broken assumption: that publishing code creates an obligation.
Historically, open source meant "here's code, use it if it helps, fix it if it breaks." No support contracts, no timelines, no moral duty. GitHub-era norms quietly inverted that into unpaid service work, with entitlement enforced socially ("be nice", "maintainers owe users").
Intrinsic motivation is the only sustainable fuel here. Once you start optimizing for users, stars, adoption, or goodwill, pressure accumulates and burnout is inevitable. When you build purely because the work itself is satisfying, stopping is always allowed, and that's what keeps projects healthy.
Hard boundaries aren't hostility; they're corrective. Fewer projects would exist if more maintainers adopted them, but the ones that remain would be stronger, and companies would be forced to fund or own their forks honestly.
Open source doesn't need more friendliness. It needs less obligation
Hey, fwiw, thank you for all of your hard work! Mockito and Powermock helped me be a big hero at one company I worked for 2011-2014. Before I arrived as a tech lead there, they had ZERO tests. The QA cycle was weeks, even months long. I instituted a whole new regime of unit and intergration testing for all the applications I was responsible for. Within one release cycle, the bug counts fell to nearly zero and the QA cycle basically became a verification step because there were no more bugs. The only way I was able to pull that off was using mocking and some clever powermock hacks because the code was otherwise untestable and thus un-refactorable. So, thanks!
>Energy drain because of JVM agent change
So funny, he essentially works for free for 10 years, then finally burns out because he doesn't want to put up with a bunch of annoying work? This is why you shouldn't work on open source unless you have a business strategy to get paid. Tons of stuff in life is 100x more annoying and exhausting if you aren't making any money. If he was making $1 million per year from this I doubt his energy would be drained.
My second project at Google basically killed mocking for me and I've basically never done it since. Two things happened.
The first was that I worked on a rewrite of something (using GWT no less; it was more than a decade ago) and they decided to have a lot of test coverage and test requirements. That's fine but they way it was mandated and implemented, everybody just testing their service and DIed a bunch of mocks in.
The results were entirely predictable. The entire system was incredibly brittle and a service that existed for only 8 weeks behaved like legacy code. You could spend half a day fixing mocks in tests for a 30 minute change just because you switched backend services, changed the order of calls or just ended up calling a given service more times than expected. It was horrible and a complete waste of time.
Even the DI aspect of this was horrible because everything used Guice andd there wer emodules that installed modules that installed modules and modifying those to return mocks in a test environment was a massive effort that typically resulted in having a different environment (and injector) for test code vs production code so what are you actually testing?
The second was that about this time the Java engineers at the company went on a massive boondoggle to decide on whether to use (and mandate) EasyMock vs Mockito. This was additionally a waste of time. Regardless of the relative merits of either, there's really not that much difference. At no point is it worth completely changing your mocking framework in existing code. Who knows how many engineering man-yars were wasted on this.
Mocking encourages bad habits and a false sense of security. The solution is to have dummy versions of services and interfaces that have minimal correct behavior. So you might have a dummy Identity service that does simple lookups on an ID for permissions or metadata. If that's not what you're testing and you just need it to run a test, doing that with a mock is just wrong on so many levels.
I've basically never used mocks since, so much so that I find anyone who is strongly in favor of mocks or has strong opinions on mocking frameworks to be a huge red flag.