Skip to content

Mockito fails to verify mocked @Service when service contains @Retryable methods #6828

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

Closed
pearj opened this issue Sep 7, 2016 · 9 comments
Closed
Labels
status: duplicate A duplicate of another issue

Comments

@pearj
Copy link

pearj commented Sep 7, 2016

I'm using spring-boot 1.4.0.FINAL and I'm having trouble when I have a mocked @Service which has @Retryable annotations in the class. When I call Mockito.verify() I get an UnfinishedVerificationException exception:

12:05:36.554 [main] DEBUG org.springframework.test.context.support.AbstractDirtiesContextTestExecutionListener - After test method: context [DefaultTestContext@5ec0a365 testClass = MockBatchTestWithRetryVerificationFailures, testInstance = sample.batch.MockBatchTestWithRetryVerificationFailures@5abca1e0, testMethod = batchTest@MockBatchTestWithRetryVerificationFailures, testException = org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at sample.batch.service.MyRetryService$$FastClassBySpringCGLIB$$7573ce2a.invoke(<generated>)

Example of correct verification:
    verify(mock).doSomething()

This looks very similar to #5837, in fact, I managed to hack to workaround based off that issue:

See: sample.batch.MockBatchTestWithRetryVerificationFailuresWorkaround.batchTest()

@Test
public void batchTest() throws Exception {
    service.process();

    if (service instanceof Advised) {
        service = (MyRetryService) ((Advised) service).getTargetSource().getTarget();
    }

    verify(service).process();
    validateMockitoUsage();
}

I have put an example project together here that reproduces this issue: https://github.com/pearj/spring-boot-batch-retry-issue
For the failure case see: sample.batch.MockBatchTestWithRetryVerificationFailures.batchTest()

Is it possible for a transparent fix somehow?

I also have this on stackoverflow

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Sep 7, 2016
@philwebb
Copy link
Member

philwebb commented Sep 7, 2016

Could you please give the latest SNAPSHOT version a quick try as we've recently fixed a number of very similar issues.

@philwebb philwebb added the status: waiting-for-feedback We need additional information before we can continue label Sep 7, 2016
@pearj
Copy link
Author

pearj commented Sep 7, 2016

How recent? I tried 1.41.SNAPSHOT today
On Wed, 7 Sep 2016 at 9:28 PM, Phil Webb notifications@github.com wrote:

Could you please give the latest SNAPSHOT version a quick try as we've
recently fixed a number of very similar issues.


You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
#6828 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAOg_dpNYC8QUEnGL9OtmL8PzPCeCOM9ks5qnp_MgaJpZM4J2ggw
.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Sep 7, 2016
@pearj
Copy link
Author

pearj commented Sep 7, 2016

1.41.BUILD-SNAPSHOT that is

@philwebb
Copy link
Member

philwebb commented Sep 7, 2016

That's the most recent. Thanks for giving it a go.

@philwebb philwebb added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Sep 7, 2016
@philwebb philwebb added this to the 1.4.1 milestone Sep 7, 2016
@wilkinsona
Copy link
Member

Looks like the build's broken so the latest snapshot is stale. Something to do with the Bamboo upgrade?

@philwebb
Copy link
Member

philwebb commented Sep 9, 2016

I don't think there's much we can do automatically when the mock method is directly used, however, if you use @MockBean with the latest snapshot then I think things will work:

@ActiveProfiles("Test")
@ContextConfiguration(classes = { SampleBatchApplication.class }, loader = AnnotationConfigContextLoader.class)
@RunWith(SpringRunner.class)
public class MockBatchTestWithRetryVerificationFailures {

    @MockBean
    MyRetryService service;

    @Test
    public void batchTest() {
        service.process();
        verify(service).process();
        validateMockitoUsage();
    }

}

@philwebb philwebb closed this as completed Sep 9, 2016
@philwebb philwebb removed this from the 1.4.1 milestone Sep 9, 2016
@pearj
Copy link
Author

pearj commented Sep 12, 2016

Thanks, Phil, you're right, @MockBean does seem to solve the problem in my example project using 1.4.0.RELEASE (doesn't appear to require the latest snapshot). Although in my actual project it didn't help for some reason, but it changed the exception from UnfinishedVerificationException: Misplaced argument matcher detected here to UnfinishedVerificationException: Missing method call for verify(mock) here when using @MockBean. But both can be solved by unwrapping Aop.

I have a helper method to unwrap aop, so I'll just use that for the moment, it's not too bad.

@snicoll snicoll removed the status: feedback-provided Feedback has been provided label Sep 12, 2016
@sbrannen
Copy link
Member

@pearj, there's no need to maintain your own helper method for that. See AopTestUtils from spring-test. 😉

@snicoll snicoll added status: duplicate A duplicate of another issue and removed type: bug A general bug labels Sep 16, 2016
@pearj
Copy link
Author

pearj commented Sep 19, 2016

@sbrannen thanks for that, although, it seems the generics in that method doesn't agree with eclipse (Eclipse Neon and Java 7), and it thinks the type is of type Object instead of the original type.

The signature is:

public static <T> T getTargetObject(Object candidate)

But I think it should be

public static <T> T getTargetObject(T candidate)

That way you can use it inline with verify without having to do any casting unless I'm missing something?

Otherwise it seems you have to do this:

((MyAopWrappedBean)verify(AopTestUtils.getTargetObject(mybean))).theMethod();

instead of just

verify(AopTestUtils.getTargetObject(mybean)).theMethod();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: duplicate A duplicate of another issue
Projects
None yet
Development

No branches or pull requests

6 participants