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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18150113/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:49:15  来源:igfitidea点击:

Casting a parameter mock object to another object using Mockito

javaandroidjunitmockito

提问by Rebane Lumes

I have a method to test, that begins following:

我有一种测试方法,从以下开始:

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

I would like to test it using Mockito, but if I declare menuInfo like this:

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

@Mock ContextMenuInfo menuInfo

then I cannot compile the following statement:

那么我无法编译以下语句:

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

since it is not valid for ContextMenuInfoobject. I cannot declare my object as AdapterView.AdapterContextMenuInfoclass, since then I get an error during run time.

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

I know that in Mockito it is possible that a mock implements multiple interfaces, but the same does not apply to classes. How would it be possible to test the method I shown above?

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

采纳答案by Jeff Bowman

Mockito works by using Java inheritanceto replace the implementations of methods on a class. However, it looks like positionis a fieldon AdapterContextMenuInfo, which means that Mockito can't mock it for you.

Mockito 的工作原理是使用 Java继承来替换类上方法的实现。然而,它看起来就像position是一个领域AdapterContextMenuInfo,这意味着能的Mockito不嘲笑它。

Luckily, AdapterContextMenuInfo has a public constructor, so you don't have to mock it—you can just create one for the test and pass it into your method.

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

@Test public void contextMenuShouldWork() {
  ContextMenuInfo info =
      new AdapterView.AdapterContextMenuInfo(view, position, id);
  systemUnderTest.onCreateContextMenu(menu, view, info);

  /* assert success here */
}

If you're ever stuck in this pattern for a class that you can't directly mock or instantiate, consider creating a helper class that you canmock:

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

class MyHelper {

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

Now you can refactor your View to use that:

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

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);
    // ...
  }
}

...and then mock the helperin your test.

...然后在您的测试中模拟助手

/** 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 */
}    

There is one other option, involving a refactor:

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

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 */
}

回答by Dawood ibn Kareem

Why don't you have a getter in AdapterView.AdapterContextMenuInfothat lets you write info.getPosition()? If you had that, then you could mock AdapterView.AdapterContextMenuInfo, stub getPosition(), then just pass the mock into the method that you're testing.

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

回答by jsphdnl

May be use mockito's extraInterfacesoption

可能使用 mockito 的extraInterfaces选项

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

and then mock it like

然后嘲笑它像

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