Mockito runnable:想要但没有被调用? [英] Mockito runnable: wanted but not invoked?

查看:72
本文介绍了Mockito runnable:想要但没有被调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在提交错误报告之前,我想确保我没有做错什么.这真的很奇怪.设置:

I want to make sure I'm not doing something terribly wrong before I submit a bug report. This is really weird. The setup:

robolectric 3.0;模拟 1.10.19

robolectric 3.0; mockito 1.10.19

被测单元:

public BbScrollView( Context context ){
  this( context, null );
}

public BbScrollView( Context context, AttributeSet attrs ) {
  super( context, attrs );

  mScrollTask = new Runnable() {

    public void run() {
      checkForStopped();
    }
  };
}

public void checkForStopped(){
  int newPosition = getScrollY();
  // the rest is irrelevant , but I hit a breakpoint here.
}

public void startScrollTask() {
  mInitialPosition = getScrollY();
  postDelayed( mScrollTask, mTimeUntilNextCheckForStopped );
}

测试:

@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class BbScrollViewTests {

  @Test
  public void test_startScrollTask(){
    BbScrollView uut = spy( new BbScrollView( RuntimeEnvironment.application ) );

    // This calls the method above that enqueues the runnable
    uut.startScrollTask();

    // Robolectric runs the runnable
    ShadowLooper.runUiThreadTasksIncludingDelayedTasks();

    // I can hit a breakpoint inside this method but verify() fails
    verify( uut ).checkForStopped();
  }
}

测试失败:

Wanted but not invoked:
bbScrollView.checkForStopped();
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:62)

However, there were other interactions with this mock:
bbScrollView.startScrollTask();
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:58)

bbScrollView.getScrollY();
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:58)

bbScrollView.$$robo$getData();
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:58)

bbScrollView.postDelayed(
    com.myapp.android.BbKit.view.BbScrollView$1@7f830761,
    100
);
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:58)

bbScrollView.$$robo$getData();
-> at com.myapp.android.BbKit.test.view.BbScrollViewTests.test_startScrollTask(BbScrollViewTests.java:58)

我再说一遍:我在 verify() 检查的方法中遇到断点,但测试失败.我还尝试在 checkForStopped() 内部创建一个虚拟方法并验证无济于事.我还在 robolectric UI 线程调用的任一侧尝试了 1000ms thread.sleep.我的猜测是 robolectric 和 mockito 的反射材料之间的相互作用正在发生什么?

I repeat: I hit breakpoints inside the method that verify() checks but the test fails. I've also tried creating a dummy method inside of checkForStopped() and verifying on that to no avail. I've also tried 1000ms thread.sleep on either side of the robolectric UI thread call. My guess is something is going on with an interaction between robolectric's and mockito's reflection stuff?

推荐答案

基于 Mockito 原则,您发现了一个非常有趣的预期但不直观的行为:要创建间谍,Mockito 对原始对象.

You've caught a really fun bit of expected-but-unintuitive behavior, based on this Mockito principle: To create a spy, Mockito makes a shallow copy of the original object.

当您在构造函数中创建匿名内部 Runnable 时,Runnable 包含对 BbScrollView.this 的隐式引用,您的 原始 BbScrollView 对象.然后,在创建 spy 时制作一个副本,并且对原始 BbScrollView 的引用仍然存在.这意味着您对 checkForStopped 的调用发生在 Mockito 无法观察到的原始对象上,而不是间谍.

When you create the anonymous inner Runnable in the constructor, the Runnable contains an implicit reference to BbScrollView.this, your original BbScrollView object. Then, you make a copy as you create the spy, and the reference to your original BbScrollView persists. This means that your call to checkForStopped happens to the original object that Mockito can't observe, not the spy.

解决此问题的一种方法是将您的匿名内部 Runnable 创建移动到您的 startScrollTask​​ 方法,在 spy 上调用,因此 this 指的是 spy.当 Runnable 运行时,它会调用 spy 上的方法而不是真实对象,从而允许 Mockito 拦截并验证调用.

One way to fix this is to move your anonymous inner Runnable creation to your startScrollTask method, invoked on the spy, so this refers to the spy. When the Runnable is run, it will call methods on the spy instead of the real object, allowing Mockito to intercept and verify the call.

这篇关于Mockito runnable:想要但没有被调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆