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

Reb*_*mes 6 java junit android mockito

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

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

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

@Mock ContextMenuInfo menuInfo
Run Code Online (Sandbox Code Playgroud)

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

Mockito.when(menuInfo.position).thenReturn(1);
Run Code Online (Sandbox Code Playgroud)

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

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

Jef*_*ica 4

Mockito 通过使用 Java继承来替换类上方法的实现。然而,它看起来像是上的position一个字段AdapterContextMenuInfo,这意味着 Mockito 无法为您模拟它。

\n\n

幸运的是,AdapterContextMenuInfo 有一个公共构造函数,因此您不必 \nmock 它\xe2\x80\x94,您只需为测试创建一个构造函数并将其传递到您的方法中即可。

\n\n
@Test public void contextMenuShouldWork() {\n  ContextMenuInfo info =\n      new AdapterView.AdapterContextMenuInfo(view, position, id);\n  systemUnderTest.onCreateContextMenu(menu, view, info);\n\n  /* assert success here */\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您曾经陷入无法直接模拟或实例化的类的这种模式,请考虑创建一个可以模拟的辅助类:

\n\n
class MyHelper {\n\n  /** Used for testing. */\n  int getPositionFromContextMenuInfo(ContextMenuInfo info) {\n    return ((AdapterContextMenuInfo) info).position;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在您可以重构您的视图以使用它:

\n\n
public class MyActivity extends Activity {\n  /** visible for testing */\n  MyHelper helper = new MyHelper();\n\n  public void onCreateContextMenu(\n      ContextMenu menu, View v, ContextMenuInfo menuInfo) {\n    int position = helper.getPositionFromContextMenuInfo(menuInfo);\n    // ...\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

...然后在测试中嘲笑助手。

\n\n
/** This is only a good idea in a world where you can\'t instantiate the type. */\n@Test public void contextMenuShouldWork() {\n  ContextMenuInfo info = getSomeInfoObjectYouCantChange();\n\n  MyHelper mockHelper = Mockito.mock(MyHelper.class);\n  when(mockHelper.getPositionFromContextMenu(info)).thenReturn(42);\n  systemUnderTest.helper = mockHelper;\n  systemUnderTest.onCreateContextMenu(menu, view, info);\n\n  /* assert success here */\n}    \n
Run Code Online (Sandbox Code Playgroud)\n\n

还有另一种选择,涉及重构:

\n\n
public class MyActivity extends Activity {\n  public void onCreateContextMenu(\n      ContextMenu menu, View v, ContextMenuInfo menuInfo) {\n    AdapterView.AdapterContextMenuInfo info =\n        (AdapterView.AdapterContextMenuInfo) menuInfo;\n    onCreateContextMenuImpl(info.position);\n  }\n\n  /** visible for testing */\n  void onCreateContextMenuImpl(int position) {\n    // the bulk of the code goes here\n  }\n}\n\n@Test public void contextMenuShouldWork() {\n  systemUnderTest.onCreateContextMenuImpl(position);\n\n  /* assert success here */\n}\n
Run Code Online (Sandbox Code Playgroud)\n