-
Notifications
You must be signed in to change notification settings - Fork 40.9k
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
@SpyBean does not work when used to spy on a Spring Data Repository #7033
Comments
Nobody cares 😢 @philwebb @wilkinsona @snicoll |
We care, we're just snowed under at the moment! The root of the problem is that @Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof FactoryBean) {
return bean;
}
return createSpyIfNecessary(bean, beanName);
} This gets us further but doesn't fix the issue because Mockto isn't able to spy on the Proxy:
|
@igormukhin is there any particular reason why you need to use |
@philwebb I stunble upon it as I worked on an integration test where I wanted to check if a specific save operation is called at the end. But still I needed that all other (find... methods) to work as usual. As a workaround I'm checking if the saved entry is in the database. |
+1. Same reason here |
+1. Same issue for the same reason (wanting to verify interactions). Using spring-data-mongo, though. |
I encountered this problem as well. I got around it by creating my mock as follows: MyClass spyOfSpringProxy = Mockito.mock(MyClass.class, AdditionalAnswers.delegatesTo(springCreatedProxy));
|
When wanting to test interactions isn't a plain unit test of the client with a mock of the repository sufficient? It wouldn't even need to be an integration then would it? It feels like you're mixing up two aspects of testing here: integration tests that check the behavior end to end and the desire to verify on internals of the tested component. I'd argue that's sort of violating the SRP principle in tests (if there is such thing in tests). Either test the thing as whole, then it's inputs against output. Or a dedicated component whose interaction with collaborators you inspect in detail. |
My specific use-case was verifying that database transactions were being rolled back as expected if a call to the repository (made in a service method) failed. Transaction was being applied as the service level. Hence I wanted to make the repository throw an exception. I wanted to use the functionality real repository most of the time except for the failure case. A spy was appropriate here. The component under test was the service but due to the nature of what it was doing, simply mocking the repository would not have been as complete a test as using a real repository. |
So were you testing that an exception within a transaction rolls back the transaction? Then you're basically testing Spring Frameworks transaction implementation, don't you? |
I'm making sure I am using Spring transactions properly. I chose to use the |
Gotcha, good point! 👍 I guess switching to a mock would then break the other tests that really want to persist data, right? |
Honestly like 99% of the time I use mocks for my dependencies (e.g. repositories) when making tests for my services. And most of the time my service methods aren't making multiple calls to a repository methods so there really is not much point in making the service method transactional. It was just this case of using the |
At the end of the day, it's not too often people have to use spies but there are cases when it's the option that gets the job done. |
Mine is just a guess, but maybe using Mockito's |
I assume you mean the |
Yeah, right! I made a test and I could only make it working by annotating the autowired beans with |
I followed @hashpyrit's advice, using a special configuration for tests. It works well and is completely decoupled from the test cases. @Configuration
public class MockRepositoryConfiguration {
@Primary
@Bean(name = "fooRepositoryMock")
FooRepository fooRepository(final FooRepository real) {
// workaround for https://github.com/spring-projects/spring-boot/issues/7033
return Mockito.mock(FooRepository.class, AdditionalAnswers.delegatesTo(real));
}
} |
This issue has been chasing milestones for 5 years now... I have seen that some specific jdk+mockito+spring version combinations appear to somehow work while other throw the UnsatisfiedDependencyExceptions. If the issue is not going to be fixed anytime soon, could we perhaps publish a list of jdk+mockito+spring version combinations that are known to work? I can confirm that: openjdk version "11.0.11-ea" 2021-04-20 + mockito-core 3.6.0 + spring-test 5.3.1 from spring boot 2.4.0 does need a workaround mentioned by @onacit |
spybean wasn't working for me once, just seems to be null. |
We have a fix for this. It's a little bit risky, but not too bad. As such, we've decided that 2.5.x is the best place for it. |
@wilkinsona thx for the fix after all this time. seems to work on my side. |
That’s a relief. Thanks for letting us know and for your patience. |
This comment was marked as off-topic.
This comment was marked as off-topic.
Im in 2.6.4/2.7.0 and @SpyBean
TestEntityRepository testEntityRepository; does not get reset across my tests when context is reused. Is easy to spot it because if you do a I double checked and Is this still expected (i've read there still were some side-effects like this besides the main bug in previous comments)? @wilkinsona BTW, nice session yesterday @snicoll on the Spring.io ! You caught me staring at you while seeking my mates, from the second floor of the staircase, I felt quite creepy xD P.S: the bean does show up on ResetMocksTestExecutionListener.resetMocks, but MockReset.get(bean) does not return AFTER, when it should, it returns NONE because SpringBootMockResolver does not find the target object . This does not happen with my other regular service @SpyBean. Ill try to attach a minimum code that reproduces it as soon as possible if you tell me it is unexpected |
@nightswimmings This issue was about the creation of the mock or spy, not resetting it. If reseting of a spied Spring Data repository isn't working for you, please open a new issue with a minimal example and we can take a look. |
Oks! If it is indeed unexpected, then I'll create the sample on a new issue, thanks! |
This comment was marked as off-topic.
This comment was marked as off-topic.
This comment was marked as resolved.
This comment was marked as resolved.
Looks like the issue is back. For me, the @SpyBean stopped working for Mongo repositories since the spring-boot-starter-parent:3.2.0 version. And everything was fine with the previous version: 3.1.10. I tried to follow the release notes, etc..., but don't see any breaking changes that may cause it. The use case is trivial. When I'm doing in test:
The exception occurs:
And flipping the version back to 3.1.10 just fixes everything. |
@pavlo-reshetniak I'm not sure you have the same problem as the only occurrence of "Specified class is an interface" in this issue is in your comment. If you have a minimal reproducer that you can share, please open a new issue and we'll take a look. |
@wilkinsona, thank you for your reply. I investigated a bit more and you are right, it's not related to the current thread. The issue is related to the generic type of the MongoRepository bean when initializing it via the @SpyBean. Regards, |
Version: Spring Boot 1.4.1
Subject:
@SpyBean
on Data Jpa Repository bean isn't workingException thrown:
Demonstration project: https://github.com/igormukhin/spring-boot-issue-6871
USE BRANCH: spybean-on-jparepository
The text was updated successfully, but these errors were encountered: