使用Mockito将参数模拟对象转换为另一个对象

时间:2013-08-09 15:17:41

标签: java android junit mockito

我有一个测试方法,开始遵循:

public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    contextString = adapter.getItem(info.position);
        /.../
    }

我想使用Mockito测试它,但是如果我声明这样的menuInfo:

@Mock ContextMenuInfo menuInfo

然后我无法编译以下语句:

Mockito.when(menuInfo.position).thenReturn(1);

因为它对ContextMenuInfo对象无效。我不能将我的对象声明为AdapterView.AdapterContextMenuInfo类,因为那时我在运行时遇到错误。

我知道在Mockito中,mock可能实现多个接口,但同样不适用于类。如何测试上面显示的方法?

3 个答案:

答案 0 :(得分:4)

Mockito使用Java 继承来替换类上方法的实现。但是,position上的@Test public void contextMenuShouldWork() { ContextMenuInfo info = new AdapterView.AdapterContextMenuInfo(view, position, id); systemUnderTest.onCreateContextMenu(menu, view, info); /* assert success here */ } 似乎是字段,这意味着Mockito无法为您模拟它。

幸运的是,AdapterContextMenuInfo有AdapterContextMenuInfo,所以你没必要 嘲笑它 - 你可以为测试创建一个并将其传递给你的方法。

class MyHelper {

  /** Used for testing. */
  int getPositionFromContextMenuInfo(ContextMenuInfo info) {
    return ((AdapterContextMenuInfo) info).position;
  }
}

如果你曾经遇到过无法直接模拟或实例化的类的模式,请考虑创建一个可以模拟的辅助类:< / p>

public class MyActivity extends Activity {
  /** visible for testing */
  MyHelper helper = new MyHelper();

  public void onCreateContextMenu(
      ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    int position = helper.getPositionFromContextMenuInfo(menuInfo);
    // ...
  }
}

现在您可以重构View以使用它:

/** This is only a good idea in a world where you can't instantiate the type. */
@Test public void contextMenuShouldWork() {
  ContextMenuInfo info = getSomeInfoObjectYouCantChange();

  MyHelper mockHelper = Mockito.mock(MyHelper.class);
  when(mockHelper.getPositionFromContextMenu(info)).thenReturn(42);
  systemUnderTest.helper = mockHelper;
  systemUnderTest.onCreateContextMenu(menu, view, info);

  /* assert success here */
}    

...然后在测试中模拟帮助

public class MyActivity extends Activity {
  public void onCreateContextMenu(
      ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    AdapterView.AdapterContextMenuInfo info =
        (AdapterView.AdapterContextMenuInfo) menuInfo;
    onCreateContextMenuImpl(info.position);
  }

  /** visible for testing */
  void onCreateContextMenuImpl(int position) {
    // the bulk of the code goes here
  }
}

@Test public void contextMenuShouldWork() {
  systemUnderTest.onCreateContextMenuImpl(position);

  /* assert success here */
}

还有一个选项,涉及重构:

{{1}}

答案 1 :(得分:3)

可以使用mockito的extraInterfaces选项

        @Mock(extraInterfaces=AdapterView.AdapterContextMenuInfo.class) 
        ContextMenuInfo menuInfo

然后嘲笑它

Mockito.doReturn(1).when((AdapterView.AdapterContextMenuInfo)menuInfo).position

答案 2 :(得分:0)

为什么AdapterView.AdapterContextMenuInfo中没有可以让你写info.getPosition()的getter?如果你有,那么你可以模拟AdapterView.AdapterContextMenuInfo,存根getPosition(),然后将模拟传递给你正在测试的方法。