robolectric 3.0 Mockito -- 如何在 activity 中模拟 class

robolectric 3.0 Mockito -- how to mock a class inside activity

我正在迁移到 robolectric 3.0

问题陈述--

我有一个 class AppUtility,它在 MyActivity 中实例化,所以要检查它的方法是否被调用,我需要在设置 MyActivity 之前在我的测试中模拟它。

这是我的代码:

@Mock
private AppUtility mockAppUtility;

@Before
public void setUp() {
    initMocks(this);
    myActivity= Robolectric.setupActivity(MyActivity.class);
    equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
    shadowActivity = Shadows.shadowOf(myActivity);
}

测试方法如下:--

  @Test
        public void shouldCallStartAlarm() {
            for (int i = 0; i < 4; i++) {
                equalsButton.performClick();
            }
            verify(mockAppUtility).startAlarm();
        }

Bu 我收到以下错误消息:-- 哪个 show mock 没有链接到 activity,我如何才能将它绑定到 activity?

Actually, there were zero interactions with this mock.

但是模拟对象与测试没有关联。对于 Robolectric 的早期版本,我使用将模拟对象关联到 activity 创建时,通过如下覆盖它

 myActivity = new MyActivity() {
                @Override
                AppUtility getUtil() {
                    return mockAppUtility;
                }
            };
            myActivity.onCreate(new Bundle());

它过去工作正常,使用 Robolectric 3.0,我如何在启动 activity 之前绑定模拟对象。

关注@nenick 你的第二个 option:This 是它的样子

    @Mock
    private AppUtility appUtility;
    @InjectMocks
    private MyActivity myActivity;
    @Before
    public void setUp() {
        ActivityController<MyActivity> activityController = Robolectric.buildActivity(MyActivity.class);
//      myActivity= Robolectric.setupActivity(MyActivity.class);
        myActivity=activityController.get();
        initMocks(this);
        activityController.setup();
        equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
//      shadowActivity = Shadows.shadowOf(calculatorActivity);
    }

但我遇到异常:-

java.lang.IllegalArgumentException: attempted to invoke public final android.app.Application org.robolectric.shadows.ShadowActivity.getApplication() on instance of class org.com.android.AppUtility$$EnhancerByMockitoWithCGLIB$c74666, but AppUtility$$EnhancerByMockitoWithCGLIB$c74666 doesn't extend ShadowActivity

it breaks at step--activityController.setup();

单元测试的主要规则之一——永远不要在测试下模拟 class。你可能会 spy 但它又是救援挑战,你不应该在这种情况下使用它。

另一个 smell 显示您已进行唤醒测试 - 当您能够 运行 此测试成功时,它不能保证真正的警报设置。它将仅保证调用此方法。因此,最好验证设置警报而不是验证方法调用。检查 this link 影子警报管理器的使用示例

使用 mockito 模拟注入功能,只需设置模拟即可。

@Mock
private AppUtility mockAppUtility;

@InjectMocks
Activity mActivity;

@Before
public void setUp() {
  myActivity= Robolectric.setupActivity(MyActivity.class);
  equalsButton = (Button) myActivity.findViewById(R.id.equals_sign);
  shadowActivity = Shadows.shadowOf(myActivity);

  // create and injects mocks into object annotated with @InjectMocks
  initMocks(this);
}

要在调用 activity 设置 (onCreate, ...) 之前设置模拟,您必须在设置之前访问您的 activity。

@Before
public void setUp() {
  ActivityController<Activity> activityController = Robolectric.buildActivity(Activity.class);

  // get the activity instance 
  mActivity = activityController.get()

  initMocks(this);

  // now setup your activity after mock injection
  activityController.setup()
}