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 · 8 comments

Comments

Projects
None yet
5 participants
@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

This comment has been minimized.

Copy link
Contributor

sdeleuze commented Jan 21, 2019

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

This comment has been minimized.

Copy link
Member

wilkinsona commented Jan 21, 2019

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

This comment has been minimized.

Copy link

vojtapol commented Jan 21, 2019

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Member

wilkinsona 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.

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.

@jnizet

This comment has been minimized.

Copy link
Contributor Author

jnizet commented Jan 21, 2019

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

@wilkinsona

This comment has been minimized.

Copy link
Member

wilkinsona commented Jan 23, 2019

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.