0

I want mock approveActivity method at the spy a spring bean.

but on this, it's not work.

  1. spring auto write object is success.

  2. spy object is success.

  3. mock method throw exception.

enter code here

I don't know why, Please help me!

SpringFramework 3.X and Mockito 2.x and Junit 4.X.

public class ActivityBasicSmokeTest extends AbstractSmockMockito4SpringTest {


    @Autowired
    private ActivityReduceAPI activityReduceAPI;

    @Test
    public void testForApprovingActivityStatus() throws FileNotFoundException {

        ActivityReduceAPI spyActivityReduceAPI = Mockito.spy(this.activityReduceAPI);

        // stop auto audit
        Mockito.doReturn(new ResultGeneralModel<>(true)).when(spyActivityReduceAPI)
            .approveActivity("1", 2L);  <---- this is throw Exception.

    }

}

ActivityReduceAPIImpl.java

@Override
public ResultGeneralModel<Boolean> approveActivity(String token, Long id) {
    try {
        AccountResponse account = sessionContext.getAccountFromTairByToken(token);
        ReduceActivityEntity activityEntity = activityService.get(id, account);
        ActivityParamUtil.validBeforeModified(activityEntity, ActivityStatusEnum.CREATE);
        Errors error = activityService.approveReduce(activityEntity, account);
        if (null != error) {
            return new ResultGeneralModel<>(error);
        }
        return new ResultGeneralModel<>(true);
    } catch (TfavatarBusException e) {
        return new ResultGeneralModel(ErrorUtil.getErrors(e));
    }
}

org.mockito.exceptions.misusing.UnfinishedStubbingException: Unfinished stubbing detected here: at com.taobao.film.tfavatar.domain.reduce.ActivityBasicSmokeTest.testForApprovingActivityStatus(ActivityBasicSmokeTest.java:458)


E.g. thenReturn() may be missing. Examples of correct stubbing:

when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();

Hints: 1. missing thenReturn() 2. you are trying to stub a final method, which is not supported 3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction is completed

at com.taobao.film.tfavatar.api.impl.ActivityReduceAPIImpl.approveActivity(ActivityReduceAPIImpl.java:192)
at com.taobao.film.tfavatar.api.impl.ActivityReduceAPIImpl$$FastClassBySpringCGLIB$$f237c997.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:701)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:93)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:633)
at com.taobao.film.tfavatar.api.impl.ActivityReduceAPIImpl$$EnhancerBySpringCGLIB$$4b39213a.approveActivity(<generated>)
at com.taobao.film.tfavatar.domain.reduce.ActivityBasicSmokeTest.testForApprovingActivityStatus(ActivityBasicSmokeTest.java:459)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:292)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.junit.runner.JUnitCore.run(JUnitCore.java:157)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
tim
  • 1
  • 2
  • 1
    can you post the code of the `ActivityReduceAPI` class ? – mehdi maick Jul 14 '19 at 09:16
  • @mehdimaick I've added it – tim Jul 14 '19 at 09:24
  • @second yes, it's not null, and it return type: ResultGeneralModel (we project api general return values) – tim Jul 14 '19 at 09:25
  • Have you tried `when(spyActivityReduceAPI.approveActivity("1", 2L)).thenReturn(new ResultGeneralModel<>(true))`? – daniu Jul 15 '19 at 14:33
  • Confirmed that the proxy that is generated has final methods and replaced my previous answer accordingly (I wonder if I just should post a new one to get rid of the - now - unrelated comments). – second Jul 15 '19 at 15:19

1 Answers1

0

Edit4: Finally after setting up a spring 3 project myself, I could verify that the methods generated by cglib indeed are final.

Printing out the methods and their modifiers of the proxy class gave me something like this:

class test.ActivityReduceAPI$$EnhancerBySpringCGLIB$$747ceb58

methods:
...
approveActivity public final
...
CGLIB$approveActivity$1 final
...

Using the CglibHelper class (found here https://www.thekua.com/atwork/2011/06/finding-real-object-under-spring-proxies/) I was able to extract the real object from the proxy. With this the test is running.

    @Test
    public void testForApprovingActivityStatus() {

        ActivityReduceAPI spyActivityReduceAPI = Mockito.spy((ActivityReduceAPI) new CglibHelper(activityReduceAPI).getTargetObject());

        Mockito.doReturn(new ResultGeneralModel<Boolean>(true)).when(spyActivityReduceAPI)
            .approveActivity("1", 2L);

        Assert.assertTrue(spyActivityReduceAPI.test("1", 2L));
    }
second
  • 4,069
  • 2
  • 9
  • 24
  • Maybe you should: https://static.javadoc.io/org.mockito/mockito-core/2.28.2/org/mockito/Mockito.html#spy – JB Nizet Jul 14 '19 at 09:30
  • sorry. i'm object is spy object. https://stackoverflow.com/questions/19798433/mockito-stubbing-outside-of-the-test-method – tim Jul 14 '19 at 09:32
  • why it's an exceptional case?? – tim Jul 14 '19 at 09:34
  • sorry, i change the code. **Mockito.when(spyActivityReduceAPI.approveActivity("1", 2L)).thenReturn(new ResultGeneralModel<>(true));** but it run the real method, so throw a NullPointException. – tim Jul 14 '19 at 09:39
  • @second NullPointException because param is not real user. **SpringFramework 3.X and Mockito 2.x and Junit 4.X.** – tim Jul 14 '19 at 09:47
  • Any specific reason why you want to use Spy. Try @InjectMocks instead of Spy. – Vinay Hegde Jul 14 '19 at 09:49
  • @VinayHegde I need this object run the other real method code. so, i could only use spy. – tim Jul 14 '19 at 09:57
  • @second thanks, but It's different from my example with me code. the **ActivityReduceAPI is a Spring proxy bean**. – tim Jul 14 '19 at 10:10
  • At least we have narrowed down the problem. It`s not the syntax that is wrong, but something with the ProxyBean instead. Maybe the proxy that is generated has final methods? – second Jul 14 '19 at 10:16
  • Removed the comments and added them to my answer. – second Jul 15 '19 at 04:54