I'm seeing the following exception when using @SpyBean
for a CrudRepository
in my Integration-Tests:
org.mockito.exceptions.base.MockitoException: VerificationStartedEvent.setMock() does not accept parameter which is not a Mockito mock.
Received parameter: org.springframework.data.jpa.repository.support.SimpleJpaRepository@1adc1d78.
See the Javadoc.
at org.springframework.boot.test.mock.mockito.SpyDefinition$SpringAopBypassingVerificationStartedListener.onVerificationStarted(SpyDefinition.java:114)
What I'm trying to do is instrument the repository to fail at a certain call to test the error handling behavior. So the definition of the field in question is as simple as it gets:
@SpyBean
private MyCrudRepository myCrudRepository;
I can use the Spy correctly for everything, with the exception of verifying whether the function was actually called, which gives me the above exception. I'm using verify
like this:
Mockito.verify(myCrudRepository, Mockito.times(1)).save(Mockito.any());
As far as I can see, that is because in SpyDefinition.SpringAopBypassingVerificationStartedListener:114 the actual object is being presented to the VerificationStartedEvent
, which actually expects a mock.
Or is that an unsupported use-case or am I spying on the repository in a wrong way?
Comment From: wilkinsona
Or is that an unsupported use-case or am I spying on the repository in a wrong way?
@RobertZenz, unfortunately it's hard to say as I'm not sure that I have understood exactly what you're trying to do. Could you please provide a complete yet minimal sample that reproduces the problem? You could share it with us by zipping it up and attaching it to this issue or pushing it to a separate repository on GitHub.
Comment From: RobertZenz
It's exactly as simple as I wrote to reproduce:
@SpringBootTest
public class Testcase {
@SpyBean
private MyCrudRepository myCrudRepistory;
@Test
public void test() {
Mockito.verify(myCrudRepistory, Mockito.times(1)).save(Mockito.any());
}
}
public interface MyCrudRepository extends CrudRepository<MyModelClass, BigDecimal> {
}
Comment From: wilkinsona
Thanks, but that isn't sufficient for us to be certain that we're looking at the same problem as you are seeing. For example, you haven't told us which version of Spring Boot you're using or of any other dependencies. If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. As I said above, you can share it with us by zipping it up and attaching it to this issue or pushing it to a separate repository on GitHub.
Comment From: RobertZenz
Thanks, but that isn't sufficient for us to be certain that we're looking at the same problem as you are seeing. For example, you haven't told us which version of Spring Boot you're using or of any other dependencies.
Given that I've pointed you at the exact line that is the problem in HEAD, I'd say "the latest".
But I'll throw something together...
Comment From: RobertZenz
This is a simple example project which shows this exception.
Comment From: wilkinsona
Thanks for the sample. It's revealed that you're using Mockito's inline mock maker, making this a duplicate of https://github.com/spring-projects/spring-boot/issues/22416.
Comment From: ractive
@wilkinsona I just ran into the same issue with spring 2.4. It seems that this issue was not a duplicate of https://github.com/spring-projects/spring-boot/issues/22416 but still exists. It seems that it's not possible to use a spring-data repository as a @SpyBean
.
I have taken the example of @RobertZenz from above and updated it to spring 2.4 to show that the error still exists: https://github.com/ractive/spring-boot-gh-23708
Will you reopen this issue or shall I create a new one?
Comment From: wilkinsona
Interesting, thanks. I'll reopen it and we can take another look. There may also be some overlap with https://github.com/spring-projects/spring-boot/issues/7033. Unfortunately, @SpyBean
and Spring Data JPA don't play together very nicely at the moment.
Comment From: ractive
Interesting, thanks. I'll reopen it and we can take another look. There may also be some overlap with #7033. Unfortunately,
@SpyBean
and Spring Data JPA don't play together very nicely at the moment.
Thanks for getting into this issue again.
BTW: We're using spring-data-mongo and see exactly the same issue.
Comment From: ractive
Another thing: In our case it worked with Spring Boot 2.3 and mockito 3.2.0 with:
@SpyBean(proxyTargetAware = false)
private MyRepository myRepository;
@Test
void someTest() {
....
verify(myRepository).findById(...):
}
With Spring 2.4 it then fails with the following error:
org.mockito.exceptions.misusing.NotAMockException:
Argument passed to verify() is of type $Proxy74 and is not a mock!
Make sure you place the parenthesis correctly!
See the examples of correct verifications:
verify(mock).someMethod();
verify(mock, times(10)).someMethod();
verify(mock, atLeastOnce()).someMethod();
at mockfailure.MockfailureTest.test(MockfailureTest.java:18)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.....
Comment From: wilkinsona
I have a possible fix for #7033 which appears to fix https://github.com/ractive/spring-boot-gh-23708. The spy is successfully created (with or without proxyTargetAware = false
). The test then fails:
org.mockito.exceptions.verification.WantedButNotInvoked:
Wanted but not invoked:
myCrudRepository.save(
<any mockfailure.data.MyModelClass>
);
-> at mockfailure.MockfailureTest.test(MockfailureTest.java:18)
Actually, there were zero interactions with this mock.
at mockfailure.MockfailureTest.test(MockfailureTest.java:18)
However, this is to be expected as nothing is interacting with the repository.
The test passes with a modification to the app such that MyCrudRepository.save(MyModelClass)
is called.
As a result of the above, I'm going to close this one as a duplicate of #7033