Skip to content
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

spring-test should handle @Mock [SPR-14083] #18655

Open
spring-issuemaster opened this issue Mar 23, 2016 · 9 comments
Open

spring-test should handle @Mock [SPR-14083] #18655

spring-issuemaster opened this issue Mar 23, 2016 · 9 comments

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Mar 23, 2016

Martin Meyer opened SPR-14083 and commented

If I have a Transaction Manager running in unit tests, it becomes impossible for Mockito to properly initialize and inject mocks. This problem seems to be related to usage of proxy classes, not specific to using a transaction manager.

Here's a basic example of a test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {EnableTransactionManager.class})
public class SomeTest {
    @Mock
    private MockBean someMockedBean;

    @Autowired
    @InjectMocks
    private RealBean someRealBean;

    @Before
    public void before() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void someTest() {
        someRealBean.doSomething();
    }
}

What I see in the debugger is that on the someRealBean.doSomething() line, someRealBean contains a mock reference to my MockBean instance. But when I set the next breakpoint within RealBean#doSomething() and go there, the local field within the object is not a mock one, it's a real @Autowire'd bean.

In real terms, the impact on me is that tests fail whenever I try to implement a TransactionManager and have it configured during tests. I end up trying to call DAO methods that should have been mocked, and it tries to issue database calls on a DataSource that isn't really ready to service them.

I think the problem is a race between Mockito and Spring to performing their setup. I think the solution is for SpringJUnit4ClassRunner to automagically call the equivalent of MockitoAnnotations.initMocks(this) if org.mockito.Mockito is in the classpath. This would mean adding an optional dependency on Mockito.

There was an issue opened against Mockito for this, which was closed as WONTFIX. They suggested that it be fixed in Spring instead of bringing in a Spring dependency there.

The obvious workaround here is to not enable anything that will do AOP proxying during your unit tests.


Affects: 4.2.5

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Aug 19, 2016

Michael Huffman commented

I do not believe this is a Spring issue. Mockito's PropertyAndSetterInjection appears to have a design flaw/limitation in that it uses field declaration of a class as a means to determine candidate injection types and properties. When a proxy is used, particularly a CGLIB proxy, the fields have no correlation to the public properties (setters) available for use in injection. Therefore, the injection filtering does not find the properties/setters suitable to inject. I have reported a comment on your original bug report in Mockito.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Nov 27, 2018

Martin Meyer commented

Has anyone looked back at this problem in the past two years? This problem persists and from a user perspective it really seems like I shouldn't have to go so far out of my way to inject mocks. Mockito has been under much heavier development lately, and with all that's changed in JUnit 5 and Spring Framework 5 maybe fixing this problem might be easier than it was when I originally filed the issue..?

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Jan 12, 2019

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

@elreydetodo

This comment has been minimized.

Copy link

@elreydetodo elreydetodo commented Jan 14, 2019

This is definitely still relevant. It has tripped up other developers on almost every project I've worked on involving Spring Framework. We always get into a state early on where unit tests aren't passing and we can't figure out why, and it always turns out it's because injecting mocks on something being proxied by cglib doesn't work as expected. Once we re-realize the problem, we start using ReflectionTestUtils to set the field, but then everyone forgets why we're doing it in some tests and not others, and we run amok using ReflectionTestUtils almost everywhere instead of @InjectMocks.

We really could use a better system to do this for us. This shouldn't be so hard and manual. Even discovering that this is a problem isn't that easy.

@philwebb

This comment has been minimized.

Copy link
Member

@philwebb philwebb commented Feb 11, 2019

@elreydetodo Have you seen the @MockBean annotation from Spring Boot?

@philwebb

This comment has been minimized.

Copy link
Member

@philwebb philwebb commented Feb 11, 2019

A similar proxy issue was raised in Spring Boot spring-projects/spring-boot#6871 with @MockBean

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Feb 18, 2019

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

@elreydetodo

This comment has been minimized.

Copy link

@elreydetodo elreydetodo commented Feb 20, 2019

Actually it looks like that would resolve the problem. I'm reading a little into that issue and the Javadoc of MockBean and MockitoTestExecutionListener, and it sounds like this thing is what I want, except for some reason it's done in Spring Boot instead of as part of the core framework.

Can we get that annotation and the test execution listener promoted to spring-test?

@elreydetodo

This comment has been minimized.

Copy link

@elreydetodo elreydetodo commented Feb 20, 2019

Please note that I'm not using Spring Boot, so I can't simply use that annotation and be done with it. Spring Boot doesn't seem like the appropriate place for such fundamental functionality to live.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.