2

I'm trying to use the @SpyBean to mock a method of a @Component and doesn't work. @MockBean works (followed the example). I've tried, read and researched many ways but couldn't make it work.

Here's the example:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment. DEFINED_PORT)
@ExtendWith(SpringExtension::class)
@Provider("MyMicroService")
@PactFolder("../../../pacts")
internal class ClientContracts {

    @SpyBean
    private lateinit var myService: MyService

    @TestTemplate
    @ExtendWith(PactVerificationInvocationContextProvider::class)
    fun pactVerificationTestTemplate(context: PactVerificationContext) {
        context.verifyInteraction()
    }

    @State("default", "NO_DATA")
    fun toDefaultState() {
        reset(processService)
    }
}

(I super simplified the test function so it's easier to read, I'd be actually doing doReturn(...).when(...).blah())

I'm always getting the "not a mock" error, because the object is always the bean wrapped by Spring CGLIB:

org.mockito.exceptions.misusing.NotAMockException: Argument should be a mock, but is: class com.blah.MyServiceImpl$$EnhancerBySpringCGLIB$$9712a2a5
    at com.nhaarman.mockitokotlin2.MockitoKt.reset(Mockito.kt:36)
...

I've tried:

  • with @SpringJUnitConfig
  • with a separate @TestConfiguration, but got resolved to same above bean
  • Using Mockito.initAnnotations(this) in a @BeforeEach
  • and more, I've tried with so many combinations that I can't remember...

Is there something that I'm missing? Or an option that I don't know?

talabes
  • 5,344
  • 2
  • 22
  • 27

1 Answers1

2
  1. Above issue is not related to the pact or pact JVM library
  2. The issue is not about spring
    • Spring - I use spring with mockito and it works, the simple example is:
import com.nhaarman.mockito_kotlin.doReturn
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.mock.mockito.SpyBean
import org.springframework.test.context.junit.jupiter.SpringExtension

@ExtendWith(value = [SpringExtension::class])
@SpringBootTest(
 webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
 classes = [Application::class]
)
internal class processorIntegrationTest : IntegrationTest() {

 @SpyBean
//    @MockBean
 private lateinit var processor: Processor;

 @Test
 internal fun abcd() {
     doReturn("something").`when`(processor).get()

     val get = processor.get()
     assertThat(get).isEqualTo("something")
 }
}
  1. Mockito - mockito_kotlin or mockito extension works with SpyBean

  2. Issue is about mockito + CGLIB

    • CGLIB - from your logs feels like class com.blah.MyServiceImpl$$EnhancerBySpringCGLIB$$9712a2a5 there is a wrapper on top of your service implementation which is SpyBean. Which means CGLIB wrapper is not and the error is for that. Try removing CGLIB wrapper and it will work
Gopinath Langote
  • 311
  • 4
  • 10
  • Thanks for taking your time for this Gopinath. The CGLIB wrapper is not something I control (and only appears with the SpyBean). How would you unwrap the service or avoid the cglib wrapper altogether? – talabes Apr 01 '19 at 12:45
  • 1
    Offcourse you can unwarp CGLIB wrapper & test Check this one for how to unwrap CGLIB https://stackoverflow.com/questions/9033874/mocking-a-property-of-a-cglib-proxied-service-not-working – Gopinath Langote Apr 01 '19 at 13:05
  • It worked. Thank you! Didn't know that there was a test utility for that. I'd still like to know the MockBean doesn't need it though. Maybe a story for another day :) – talabes Apr 01 '19 at 23:13
  • Good to hear that. – Gopinath Langote Apr 02 '19 at 08:04