Search code examples
spring-bootkotlinpactpact-jvm

@SpyBean not working with Pact and JUnit 5


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?


Solution

    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