hientran1985 / mockito

Automatically exported from code.google.com/p/mockito
0 stars 0 forks source link

Incorrect result of verify() on spied transactional objects #253

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
I am using Mockito for integration tests, "spying" on method invocations in 
real Spring beans. I created Spring BeanPostProcessor (attached) that wraps 
Spring beans in spy proxy. Everything works fine on regular beans, however when 
Mockito wraps beans that are already wrapped by Spring (e.g. DAO's 
@Transactional), then calling veriyZeroIntractions(bean) always passes even if 
there were calls on the spied bean.

What steps will reproduce the problem?

1. Configure Spring beans to be wrapped by Mockito.spy (using 
BeanPostProcessor). One of this beans is DAO annotated with @Transactional

2. Force Spring to proxy classes instead of interfaces (<tx:annotation-driven 
proxy-target-class="true" />)

3. @Autowire these beans in JUnit integration test:
@Autowire
private MyDao dao;

4. Inside test method call dao (even explicitly):
dao.getFooById(1);

5. call verifyZeroInteractions(dao)

What is the expected output? What do you see instead?

Verification should fail, but it passes.

What version of the product are you using? On what operating system?
1.8.5 (Spring 3.0.5-RELEASE)

Please provide any additional information below.

Original issue reported on code.google.com by itle...@gmail.com on 31 Mar 2011 at 5:27

Attachments:

GoogleCodeExporter commented 8 years ago
Could be difficult to resolve.

1. I'm assuming no verifications actually work when in this double-proxy case?
2. Is mockito proxy the outer proxy?
3. Wouldn't you prefer to have a simpler test that does not utilize Spring 
proxy mechanisms?

Cheers :)

Original comment by szcze...@gmail.com on 3 Apr 2011 at 11:23

GoogleCodeExporter commented 8 years ago
1. It looks like no interactions are recorded on mock/spy in double-proxy case, 
so any call to verify() fails and any call to verifyZeroInteractions() always 
succeeds regardless of whether mocked/spied methods were called or not.

2. Yes, Mockito is the outer proxy

3. We also have simple traditional unit tests without any Spring stuff. 
Here is slightly different use case, let me describe the idea:

-   We want to have high-level functional tests, which "view" entire system as a 
black box. 
-   We simulate and verify only "edge" points (DB, JMS, calls to external 
subsystems). 
-   Such tests describe the system from biz perspective, they are very stable and 
as a result help during refactoring.
-   We verify persistent data in DB directly (JDBC call in the test) 
-   We use Mockito's spies to verify calls to external API (web services, JMS, 
etc.). 
-   We also use spies to verify that there are no redundant calls to DAOs (proper 
caching is in place)

Original comment by itle...@gmail.com on 4 Apr 2011 at 2:10

GoogleCodeExporter commented 8 years ago
Ok i see your point. I wonder if it is possible to reproduce it without spring. 
Would you be able to provide us a simple project zip with a test that 
reproduces this behavior? This problem may be fixable but there is a chance we 
hit cglib limitations.

Original comment by szcze...@gmail.com on 7 Apr 2011 at 7:57

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
Any progress on this issue. I have similar settings (@Transactional 
double-proxy case). But the problem in my case is that the real method is 
called during spyied method behaviour configuration with 
doAnswer(...).when(spyiedObject).method(any(Type.class));

Any ideas ?

Original comment by Bartosz....@gmail.com on 20 Sep 2012 at 10:26

GoogleCodeExporter commented 8 years ago
Can you provide a self-contained small project that reproduces the problem? 
Alternatively, if you can reproduce the behavior in your environment you could 
debug into Mockito and submit a patch? :)

Cheers!

Original comment by szcze...@gmail.com on 20 Sep 2012 at 1:57

GoogleCodeExporter commented 8 years ago
I have the same problem with bean that has some method annotated with 
@Cacheable. 

@Component
public class DemoService {

    private static final Logger log = LoggerFactory.getLogger(DemoService.class);

    public boolean getTrue() {
        log.info("getTrue");
        return Boolean.TRUE;
    }

     @Cacheable("testCache")
    public boolean getValueFromCache() {
        return true;
    }

Why I try to execute:

doReturn(false).when(demoServiceSpy).getTrue();

the getTrue method of DemoService is called and  it is not mocked up.

Attached is the sample project.

Original comment by predrag....@gmail.com on 26 Dec 2012 at 12:09

Attachments:

GoogleCodeExporter commented 8 years ago
I also have the same problem with :

@MessageEndpoint
public class RmsStdAlcEndpoint {
   @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
   public Long processMessage(Message<RmsStdAlc> message) {
      //business logic
      return 0L;
   }
}

when verifing like this in test class: 
verify(rmsStdAlcEndpoint).processMessage(Matchers.any(Message.class));

medhod is re-called with null message value so NullPointerException is thrown.

Original comment by bola...@gmail.com on 30 Jun 2014 at 1:36

GoogleCodeExporter commented 8 years ago
Please demonstrate the issue on a simple project, like on github. TIA

Original comment by brice.du...@gmail.com on 24 Jul 2014 at 6:36