Search code examples
javamockitoanonymous-classverifymethod-call

Mockito: verifying method call from internal anonymous class


I have a class under test which contains a method which has an inner anonymous class. One of the methods in the anonymous class calls a method from the class under test, but Mockito doesn't seem to realize this.

public class ClassUnderTest {
    Dependency dependency;
    public ClassUnderTest(Dependency d) {
        dependency = d;
    }
    public void method() {
        dependency.returnsObservable().observeOn(AndroidSchedulers.mainThread())
            .subscribeOn(Schedulers.io()).subscribe(new Observer<SupportClass> {

            /* Other methods omitted */
            public void onComplete() {
                 outerMethod();
            })
    }

    public void outerMethod() {
        blah;
    }
}

My test code:

public class TestClass {

    ClassUnderTest underTest;
    Dependency dependency;

    @Before
    public void setUp() throws Exception {

        dependency = Mockito.mock(Dependency.class);
        underTest = Mockito.spy(new ClassUnderTest(dependency));

    }

    @Test
    public void method() throws 
        Mockito.when(dependency.returnObservable()).thenReturn(Observable.just(new SupportClass());

        Mockito.doNothing().when(underTest).outerMethod();

        underTest.method();
        Mockito.verify(underTest).outerMethod();

    }

}

For some reason that I can't seem to figure out, Mockito can't detect that outerMethod() is being called, even though I have manually verified by stepping through line by line in the debugger. I have also verified that the call to the dependency object returns the proper observable with the correct content, and the onComplete() and outerMethod() methods do get called. I'm just confused why Mockito doesn't detect it as such.

This is the error that it spits out:

Wanted but not invoked:
classUnderTest.outerMethod();
-> at (file and line number)

However, there was exactly 1 interaction with this mock:
classUnderTest.method();
-> at (file and line number)

Is there anything obvious I'm missing?


Solution

  • You're changing between schedulers so it can cause some issues when testing (your code may reach the verify method before the actual method is invoked

    Check this article explaining how to test asynchronous code with RxJava and Mockito

    TL;DR

    Add a TestRule that set all schedulers to trampoline so it behaves synchronously:

    public class TrampolineSchedulerRule implements TestRule {
      @Override
      public Statement apply(final Statement base, Description d) {
        return new Statement() {
          @Override
          public void evaluate() throws Throwable {
            RxJavaPlugins.setIoSchedulerHandler(
                scheduler -> Schedulers.trampoline());
            RxJavaPlugins.setComputationSchedulerHandler(
                scheduler -> Schedulers.trampoline());
            RxJavaPlugins.setNewThreadSchedulerHandler(
                scheduler -> Schedulers.trampoline());
            RxAndroidPlugins.setInitMainThreadSchedulerHandler(
                scheduler -> Schedulers.trampoline());
    
            try {
              base.evaluate();
            } finally {
              RxJavaPlugins.reset();
              RxAndroidPlugins.reset();
            }
          }
        };
      }
    }