在 Mockito / Powermock 中访问匿名 Runnable 实例

Access anonymous Runnable instance in Mockito / Powermock

这是我的测试代码:

Activity activityMock = Mockito.mock(TestActivity.class);    

doAnswer(new Answer() {
     @Override
     public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
     Object[] args = invocationOnMock.getArguments(); // ->>>> args contains one Foo instance called "foo"
     return invocationOnMock;
  }
}).when(activityMock).runOnUiThread(any(Runnable.class));

runDialogOnUiThread(activityMock, new Foo());

到以下生产代码:

public static void runDialogOnUIThread(final Activity activity, final Foo foo) {
    activity.runOnUiThread(new Runnable() {
        @Override public void run() {
            doSmth();
        }
    });
}

查看我在测试代码中的评论。我期望 invocationOnMock.getArguments() 到 return Runnable 实例,但它是 returning Foo 实例(这对我来说完全没有意义)?

我以为

doAnswer(new Answer(){..}).when(b).bMethod(any(C.class)) 

在 b 上的任何地方调用 bMethod() 时拦截,它将 C.class 的实例传递给 doAnswer() 以使其在 "new Answer().."-Callback 中可用..

如何访问在生产代码中创建的匿名 Runnable 实例?

我猜你的匿名 Runnable 实例是在 Foo 中定义的,对吗?

这是我为重现您的问题而编写的一些代码:

public class MockitoTest {

    @Test
    public void test() {
        final Activity activityMock = Mockito.mock(TestActivity.class);

        doAnswer(new Answer() {
             @Override
             public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
                 final Object[] args = invocationOnMock.getArguments();
                 System.out.println("Is argument a Runnable? " + (args[0] instanceof Runnable));
                 System.out.println("What is the argument toString()? " + args[0].toString());
                 return invocationOnMock;
             }
        }).when(activityMock).runOnUiThread(any(Runnable.class));

        runDialogOnUIThread(activityMock);
    }


    public void runDialogOnUIThread(final Activity activity) {
        final Runnable r = new Runnable() {
            @Override public void run() {
                System.out.println("***");
            }};
        activity.runOnUiThread(r);
    }

    public static interface Activity {
        void runOnUiThread(Runnable r);
    }

    public static class TestActivity implements Activity {
        @Override
        public void runOnUiThread(final Runnable r) { r.run(); }
    }

}

几乎相同的东西,但它被删减以说明我认为您感到困惑的地方。

输出为:

Is argument a Runnable? true
What is the argument toString()? Whosebug.MockitoTest@6b143ee9

请注意,第二个输出包含 toString() 输出的 MockitoTest,但与 Runnable 无关。那是因为 toString() 方法没有在匿名 Runnable.

中明确定义

让我们将 Runnable 更改如下:

    final Runnable r = new Runnable() {
        @Override public void run() {
            System.out.println("***");
        }

        @Override public String toString() {
            return "ANON RUNNABLE";
        }
    };

则输出为:

Is argument a Runnable? true
What is the argument toString()? ANON RUNNABLE

我怀疑您被绊倒的是 toString() 输出看起来与创建匿名 Runnable 的 class 名称相同 class。