Search code examples
javaspring-boottestingspockspy

How to use spock @SpringSpy with a JpaRepository


I am using spring boot with jpa and spock. I want to assert that certain calls were made to the repo as a functional test, so a Mock won't do (I need to verify that a native query works with certain test data in the DB).

I have tried a @SpringBootTest with the field:

@SpringSpy
MyJpaRepository repo

and within the test method:

interaction {
        1 * repo.someMethod(_) 
}

where MyJpaRepository extends JpaRepository<Foo, Long>, but when I run the test I get:

Cannot create mock for class com.sun.proxy.$Proxynnn because Java mocks cannot mock final classes. If the code under test is written in Groovy, use a Groovy mock.

Other than this error, all my functional tests work, so it's not a config issue.

How can I spy on an @Autowired bean?


Solution

  • When using @SpringSpy on a Spring Bean that is Spring is proxying already, you need to unwrap that proxy. This is done via @UnwrapAopProxy

    @UnwrapAopProxy
    @SpringSpy
    MyJpaRepository repo
    
    void "spying on a repo works"() {
      when:
      repo.getById(1L)
    
      then:
      1 * repo.getById(_)
    }
    

    This is mentioned in the comments, but nobody submitted an answer and I spent a lot of time trying to find the answer because I didn't read the comments the first time I landed here.

    This blog post also was very helpful. If you are concerned about reusing the Spring Context so your tests don't slow down, then you might want to consider the other options presented in this post.