【问题标题】:Providing mocked object to another mock object constructor?将模拟对象提供给另一个模拟对象构造函数?
【发布时间】:2018-04-29 11:42:56
【问题描述】:

第一次进行单元测试,并使用 Mockito。我不确定我是否正在考虑正确测试它。情况如下:

在我的 Android 应用中,我使用的是 Model-View-Presenter。我正在尝试在我的演示者类中测试一个名为 validateCredential(serviceManager: ServiceManager, email: String, password: String) 的方法,以查看我传递给它的服务管理器是否最终会通过使用 mockito 进行验证来调用回调(该方法由视图调用)。

// method in presenter class
override fun validateCredential(serviceManager: ServiceManager, email: String, password: String) {
    loginModel = LoginModel(email, password)
    serviceManager.getParent(email, password)
    serviceManager.execute()
}

// callback implemented by presenter class
private fun handleLoginResult(result: ServiceManager.RequestResult, data: ByteArray, responseCode: Int, optionalParam: String) {
    ...
    mView.startHomeScreen()
}

presenter 类还实现了一个回调接口 (IServiceAsyncTaskCallback),该接口提供给 serviceManager 的构造函数。我想要在这个特定的单元测试中验证是否调用了 mView.startHomeScreen()

问题:

  • Android 单元测试似乎需要对 ServiceManager 进行模拟(ServiceManager 扩展抽象类 AsyncTask),因为当我调用 execute() 时,如果没有模拟,Android 单元测试库会抛出异常。
  • 但是,如果我模拟 ServiceManager,我无法向构造函数提供两个必要的参数,如果我正确理解单元测试,则应该模拟这些参数。构造函数的两个参数是一个接口回调(也就是presenter类),以及一个负责通过http发送JSON的类对象。这两个都应该被嘲笑,对吗?因为在单元测试中,您不希望这些依赖项实际进行 HTTP 调用或调用回调,对吧?
  • 看来我想多了。我真正想要的是查看传递给演示者的视图对象是否调用startHomeScreen(),所以我真的应该忘记测试validateCredentialMethod(),直接调用handleLoginResult(...)。这比上面的路线好吗?
  • 然而,另一个问题是即使我直接调用handleLoginResult(...)来测试是否调用了传递给presenter的模拟视图,该方法代码包含对Android相关代码JSONObject的调用,并且由于它属于android.jar 文件,它会抛出异常,因为它没有被模拟!我也应该为此提供注射吗?!

我不知道如何测试这个。验证模拟视图是否调用了startHomeScreen() 的正确方法是什么?

【问题讨论】:

  • 刚刚发布了一个答案...如果这回答了您的问题,您可能需要编辑标题,因为我认为它不能反映您的实际问题

标签: java android unit-testing kotlin mockito


【解决方案1】:

问题是您试图在一个单元测试中测试两个单独的类,这使得它不是单元测试。

根据您当前的设置,您似乎想要在 2 个不同的类中拥有 3 个不同的测试用例(组成名称,尽量明确其内容):

  • PresenterTest

    • testThatServiceManagerIsExcecutedOnValidateCredential
    • testThatStartHomeScreenIsCalledWhenHandlingLoginResult
  • 服务管理器测试

    • testCallbackIsCalledOnExcecuted

【讨论】:

  • 好的。说得通。对于testCallbackIsCalledOnExecuted(),我将如何处理对引发异常的JSONObject() 构造函数的调用(因为它属于android.jar)?我是否必须将其作为模拟注入某处?如果是这样,每当我调用属于 android.jar 测试版本的东西时,似乎都会有无穷无尽的模拟。
  • 我需要更多关于您的 ServiceManager 的背景信息。一般来说,你可以做的是将你对 Android 方法的调用包装在你自己的类中,然后你可以模拟它(例如创建一个 JSONObjectFactory,它调用 JSONObject(),但在测试中模拟它来做你想做的任何事情。跨度>
  • 对于在 Android 中调用静态方法的情况,可以使用 PowerMockito:stackoverflow.com/questions/21105403/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-19
  • 2017-06-02
  • 2010-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多