最终 class 方法未按需要使用 Mockito 2 进行测试
Final class method not getting tested as desired with Mockito 2
如Mockito 2 docs中所述,我们现在可以模拟最终classes,所以我尝试在一个简单的项目中这样做,但结果并不合适。
这是我的项目结构
这是 org.mockito.plugins.MockMaker 文本文件
mock-maker-inline
这是一个演示 activity 用于测试
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
}
private fun onLoginPressed(email:String, password:String){
}
fun isEmailValid(email: String):Boolean{
return true
}
}
这里是测试class
class LoginActivityTest{
@Test
fun checkLoginValidity(){
val lognActivity = Mockito.mock(LoginActivity::class.java)
assert(lognActivity.isEmailValid("yuo"))
}
}
测试应该已经通过了,因为我总是返回 true,但这是我得到的结果。
我也标记和取消标记资源目录作为测试资源根目录,但实际上没有发生任何事情。
你能指出我哪里错了吗?
Mocking final (Kotlin) classes 和 Mockito 工作正常,你的设置显然是正确的(如果 mocking Activity
失败,你会得到一个错误)。您尝试测试的方式有问题。
Mockito 用于模拟要测试的 class 的 依赖项 ,而不是要测试的 class 本身。
你在那里做的是嘲笑你的 LoginActivity
,然后断言它 return 有一些价值。对于 return 和 boolean
类似 isEmailValid(...)
的方法,默认为模拟 returns false
。
你不测试模拟,那没有意义。您想要测试被测 class 的 'real' 实例。
如果您想测试 Activity
,您只需使用 val classToTest = LoginActivity()
创建一个,然后执行您的 assert
。
这可能(不确定)适用于这种非常简单的情况,但通常您不会对 Activity
进行单元测试,因为有太多 Android 特定的东西在进行,比如膨胀布局(setContentView
),这在单元测试中不起作用。
这就是为什么像 MVP 或 MVVM 这样的概念越来越受欢迎,将尽可能多的逻辑从 Android-class 中移开,例如 Activity
,然后使其可测试。
对于你的情况,为了让你开始,你可以写一个 EmailChecker
class 你是。然后在你的 Activity 中使用来检查电子邮件 String
和 b。可以用单元测试更好的测试。
你嘲笑了你的 Activity
class,所以它的所有方法总是 returns "default" 值(boolean
是 false
) .你需要说 Mockito
来调用 class.
的真实方法
`when`(lognActivity.isEmailValid(ArgumentMatchers.any() ?: ""))
.thenCallRealMethod()
顺便说一句,最好只将该解决方案用于抽象 classes,因为您不能用其他方法创建它的实例。如果你的 class 不是抽象的,就创建它(为了 Activity
测试更好地使用 specific tools)。
如Mockito 2 docs中所述,我们现在可以模拟最终classes,所以我尝试在一个简单的项目中这样做,但结果并不合适。
这是我的项目结构
这是 org.mockito.plugins.MockMaker 文本文件
mock-maker-inline
这是一个演示 activity 用于测试
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
}
private fun onLoginPressed(email:String, password:String){
}
fun isEmailValid(email: String):Boolean{
return true
}
}
这里是测试class
class LoginActivityTest{
@Test
fun checkLoginValidity(){
val lognActivity = Mockito.mock(LoginActivity::class.java)
assert(lognActivity.isEmailValid("yuo"))
}
}
测试应该已经通过了,因为我总是返回 true,但这是我得到的结果。
我也标记和取消标记资源目录作为测试资源根目录,但实际上没有发生任何事情。
你能指出我哪里错了吗?
Mocking final (Kotlin) classes 和 Mockito 工作正常,你的设置显然是正确的(如果 mocking Activity
失败,你会得到一个错误)。您尝试测试的方式有问题。
Mockito 用于模拟要测试的 class 的 依赖项 ,而不是要测试的 class 本身。
你在那里做的是嘲笑你的 LoginActivity
,然后断言它 return 有一些价值。对于 return 和 boolean
类似 isEmailValid(...)
的方法,默认为模拟 returns false
。
你不测试模拟,那没有意义。您想要测试被测 class 的 'real' 实例。
如果您想测试 Activity
,您只需使用 val classToTest = LoginActivity()
创建一个,然后执行您的 assert
。
这可能(不确定)适用于这种非常简单的情况,但通常您不会对 Activity
进行单元测试,因为有太多 Android 特定的东西在进行,比如膨胀布局(setContentView
),这在单元测试中不起作用。
这就是为什么像 MVP 或 MVVM 这样的概念越来越受欢迎,将尽可能多的逻辑从 Android-class 中移开,例如 Activity
,然后使其可测试。
对于你的情况,为了让你开始,你可以写一个 EmailChecker
class 你是。然后在你的 Activity 中使用来检查电子邮件 String
和 b。可以用单元测试更好的测试。
你嘲笑了你的 Activity
class,所以它的所有方法总是 returns "default" 值(boolean
是 false
) .你需要说 Mockito
来调用 class.
`when`(lognActivity.isEmailValid(ArgumentMatchers.any() ?: ""))
.thenCallRealMethod()
顺便说一句,最好只将该解决方案用于抽象 classes,因为您不能用其他方法创建它的实例。如果你的 class 不是抽象的,就创建它(为了 Activity
测试更好地使用 specific tools)。