Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MockK #15749

Closed
jnizet opened this issue Jan 21, 2019 · 18 comments
Closed

Add support for MockK #15749

jnizet opened this issue Jan 21, 2019 · 18 comments
Labels
status: declined A suggestion or change that we don't feel we should currently apply

Comments

@jnizet
Copy link
Contributor

jnizet commented Jan 21, 2019

Spring Boot provides @MockBean and @SpyBean annotations for integration tests, which create mock/spy beans using Mockito.

Even though Mockito is a fantastic mocking library, it's been written with Java in mind, and a long time ago. MockK is becoming a quite popular alternative for code written in Kotlin, and provides (IMHO) a cleaner and safer DSL than Mockito for Kotlin.

Although it's perfectly usable in Spring Boot tests already, Spring Boot doesn't provide equivalent annotations for MockK, and tests are thus a more cumbersome to write: beans must be manually defined using a @TestConfiguration-annotated nested class, and care must be taken to reset the mocks after each test execution.

It would be nice if Spring Boot provided equivalent annotations for MockK, since Kotlin is a now a first-class citizen in Spring Boot.

The good news (or at least, I hope so)

I have created a SpringMockK library doing just that. The linked README describes the principle of the library (how it's been created), its limitations, and the differences with Mockito.

I would very much like that code to disappear from my repo and be integrated into Spring Boot.

Please tell if that would be possible, and how to proceed.

In addition to what the README contains, here is an additional useful indication: it's possible to mix Mockito tests and MockK tests in the the same project (which can be handy during a migration).

@sdeleuze
Copy link
Contributor

Just for the context, I agree that MockK is indeed more and more the default way to mock in Kotlin, I am not super happy about Mockito Kotlin support, and I would be in favor of promoting MockK as the recommended solution if such feature would be part of Spring Boot in our documentation and tutorial.

@wilkinsona
Copy link
Member

We had a similar request in the past, but it was more focused on Spock. It was also looking to map @MockBean and @SpyBean onto Spock rather than introducing new annotations as SpringMockK does. I think that difference goes quite a long way to alleviate the concerns about making Boot's existing code more complex, but it does introduce the possibility of confusion about using @MockBean or @MockKBean. A benefit of SpringMockK being separate from Spring Boot is that @MockKBean will only be offered by your IDE if you've decided to use it and added a dependency.

@vojtapol
Copy link

I don't see why we need the equivalent of @MockBean. We use MockK extensively in our Spring Boot tests. We provide them in @Configuration classes like so:

@Bean
@Primary
fun service() = mockk<Service>(relaxed = true)  // or unrelaxed with specific behavior defined here

In the tests themselves, we inject the mocks via @Autowired and record/verify the desired behavior.


That being said I am all for promoting MockK. In my opinion, Mockito Kotlin is awful and should have been deprecated in favor of MockK long time ago.

At the very least we should definitely exclude it from all Kotlin Spring tutorials.

@jnizet
Copy link
Contributor Author

jnizet commented Jan 21, 2019

English is not my mother language, and I'm not sure I understand what "I think that difference goes quite a long way to alleviate the concerns about making Boot's existing code more complex" means.

Regarding the usage of separate annotations, here's what I can say:

  • MockBean and SpyBean are tightly coupled with Mockito (its answer attribute uses a Mockito type, its MockReset enum also exposes the Mockito API)
  • Having two separate sets of annotations allows the possibility of using the two frameworks in parallel
  • MockkBean and MockBean are indeed quite confusing, but I haven't found any better name to make the distinction more obvious.

In the long run, maybe it would be a good idea to extract the Mockito support and the MockK support (and any other mocking library that would be supported in the future) into additional starters, so that one could pick Mockito, or MockK, or both.

I'm currently excluding the mockito-core dependency of spring-boot-starter-test, and the IDE thus makes it clear that MockBean is a mistake because it can't find its dependencies.

@jnizet
Copy link
Contributor Author

jnizet commented Jan 21, 2019

@vojtapol I agree that MockkBean is not strictly needed. You can indeed use configuration classes to define the mocks (and that's what I currently do, too).

But the same could be said of MockBean: it's not strictly needed either, and you could also define the Mockito mocks using configuration classes.

Still, they're quite handy and idiomatic. Another advantage of the annotation support is that mocks are properly reset automatically between test executions.

@wilkinsona
Copy link
Member

English is not my mother language, and I'm not sure I understand what "I think that difference goes quite a long way to alleviate the concerns about making Boot's existing code more complex" means.

Sorry, let me have another go and see if I can explain myself more clearly.

The proposal in #9372 was to allow @MockBean and @SpyBean to be used with mocking libraries other than Mockito, with a specific focus on Spock. This would have required the existing support for @MockBean and @SpyBean to adapt to whatever's on the classpath and delegate to a Mockito-based implementation or a Spock-based implementation as appropriate. That's quite a bit of extra complexity in the implementation and some for users too. This extra implementation complexity is avoided in the approach you've taken with SpringMockK so it avoids one of the main concerns that resulted in #9372 being declined.

There's still some extra complexity for users in terms of the two different sets of similar annotations. As you've suggested, that could be avoided by splitting things up a bit more so that it's easier for users to have finer-grained control of the classpath. That has some downsides of its own though.

I'll flag this one for team attention as whether or not we add something like this is quite subjective. We'll need to try and reach a decision that everyone on the core team is happy with.

@wilkinsona wilkinsona added the for: team-attention An issue we'd like other members of the team to review label Jan 21, 2019
@jnizet
Copy link
Contributor Author

jnizet commented Jan 21, 2019

Thanks for the explanation @wilkinsona. Let's see what the team decides now :-)

@wilkinsona
Copy link
Member

We discussed this today, and decided that we don't think the time is right to incorporate it into Spring Boot. Thanks anyway for the offer and best of luck with the SpringMockK project. Having reviewed things again, we're, if anything, leaning towards moving @MockBean and @SpyBean out of a Mockito-specific package and making them mocking framework agnostic. That's not something that we expect to tackle in the short or even medium term.

@emersonf
Copy link

emersonf commented Sep 1, 2020

Any chance this decision can get reconsidered, given the adoption of Kotlin over the last couple of years? It's a bit jarring to have Mockito support but not Mockk support, and it feels odd to require third-party dependencies for something as basic as mocking a collaborator bean.

From a readability standpoint, while it's possible to make do without the library, this:

    @MockBean
    private lateinit var fooService: FooService

reads a whole lot better than this:

    @TestConfiguration
    class AdditionalConfiguration {

        @Bean
        @Primary
        fun mockFooService(): FooService =  mockk()
    }

    @Autowired
    private lateinit var fooService: FooService

And while the code isn't hitting production systems, moving it under the Spring Boot umbrella would also give SecOps additional peace of mind that there are more eyes on it.

@philwebb philwebb added the for: team-attention An issue we'd like other members of the team to review label Sep 1, 2020
@vojtapol
Copy link

vojtapol commented Sep 2, 2020

I think that if the Spring Boot team does not want to support MockK then the dependency on Mockito should be also deprecated and removed. There is no reason to give Mockito any special treatment. In fact, MockK is a much better library, with better API design and is easier to use than Mockito at least when using Kotlin.

@wilkinsona
Copy link
Member

The data that we have from start.spring.io tells us that the vast majority of Spring Boot applications are written in Java and Mockito is the most widely used mocking library for applications written in Java. While I can understand that you are frustrated, it doesn't make sense to remove support for Mockito purely because there are better alternatives for Kotlin users. It would be detrimental for Spring Boot users who choose to use Java while providing no benefit to those who choose to use Kotlin.

@wilkinsona
Copy link
Member

wilkinsona commented Sep 3, 2020

@emersonf We've flagged this one for team attention again. From my perspective at least, I'd still lean towards moving @MockBean and @SpyBean out of a Mockito-specific package and making them mocking framework agnostic. As above, that's not something that we expect to tackle in the short or even medium term.

@christian-german
Copy link

christian-german commented Sep 3, 2020

I just subscribed to some spring repositories in order to try to contribute to some of spring related projects and OSS in general, mainly Java but a bit of Kotlin too as I'm working on some Android apps.
This issue caught my attention as I'm currently working on passing the Spring pro exam and diving into the Spring philosophy.

To me, choosing the implementation based on what's present in the classpath is what's spring-boot's autoconfiguration is all about. This should goes the same for the mocking framework.

@philwebb
Copy link
Member

We discussed this again today in our team meeting and decided that we unfortunately don't have the bandwidth to develop and maintain MockK support in Spring Boot itself. We believe this feature is still best served by the community.

@philwebb philwebb removed the for: team-attention An issue we'd like other members of the team to review label Sep 18, 2020
@emersonf
Copy link

Fair enough. Thanks for taking the time to discuss it and for the transparency. 🙂

@ianbrandt
Copy link

ianbrandt commented Mar 22, 2023

The data that we have from start.spring.io tells us that the vast majority of Spring Boot applications are written in Java and Mockito is the most widely used mocking library for applications written in Java.

I'm curious if the Kotlin use has ticked up at all over the past few years.

I work on a project that's incrementally migrating from Java to Kotlin, so presumably that wouldn't show up in the start.spring.io stats.

From my perspective at least, I'd still lean towards moving @MockBean and @SpyBean out of a Mockito-specific package and making them mocking framework agnostic.

It's not mandated, but my fellow developers are choosing to write new tests almost exclusively in Kotlin. There are often existing Java tests in the same modules, though. Having to choose whether @MockBean was satisfied with Mockito or MockK on a per-classpath basis would be problematic, since 'src/test/java' and 'src/test/kotlin' typically share the same classpath in that scenario (at least with Gradle, and I believe with Maven as well).

I do wish @MockBean and @MockKBean were easier to visually distinguish. Also, for test suites written in all Kotlin, that it wasn't so easy to accidentally autocomplete @MockBean instead of @MockKBean.

Maybe @MockitoBean and @MockKBean wouldn't be such a bad idea. They have different stubbing and verification APIs, so it'd be helpful to have a visual cue as to which you're working with.

@PandaGeek1024
Copy link

We have written all our projects in kotlin and will never go back to java again. Would you reconsider to raise this again considering the popularity of kotlin in these days.

@wilkinsona
Copy link
Member

Spring Boot's @MockBean and @SpyBean will be deprecated in 3.4 in favor of their @MockitoBean and @MockitoSpyBean equivalents that are new in Spring Framework 6.2. The new names will hopefully remove some of the confusion caused by @MockBean and @MockKBean having such similar names.

Beyond this, little has changed from Spring Boot's perspective. Judging by the data that we have, the overwhelming majority of applications continue to use Java. It also remains the case that we don't have the bandwidth to support MockK directly. Even if we did, it makes less sense to do so now given the functionality is moving into Spring Framework. If this functionality was to be added to a Spring project, Spring Framework now feels like the natural home for it. However, to me, this still feels like a feature that is best-served by the community. The Spring Framework team may have a different perspective but I cannot speak for them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined A suggestion or change that we don't feel we should currently apply
Projects
None yet
Development

No branches or pull requests

10 participants