自定义 JUnit 规则允许所有测试无论如何都通过
Custom JUnit Rule allows all tests to pass no matter what
我有一个文件引用了一些静态方法:
class MyViewModel {
fun test() { }
companion object {
private val MY_STRING = ResourceGrabber.grabString(R.string.blah_blah)
}
}
在我对此文件的 JUnit 测试中,我编写了一些代码来模拟设置中的资源采集器。这编译和 运行s,下面的测试失败了,正如我所期望的那样:
@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
PowerMockito.mockStatic(ResourceGrabber::class.java)
val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)
whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
val res: Int? = invocation?.arguments?.get(0) as? Int
TestResourceGrabber.grabString(res)
}
viewModel = MyViewModel()
}
@Test
fun someTest() {
// Fails, as expected.
assertEquals(2, 3)
}
}
这里是事情变得奇怪的地方。我最近了解了自定义 JUnit 规则,您可以使用这些规则来避免测试中出现一些重复代码。在这种情况下,我不想将我的资源采集器工作复制并粘贴到使用它的每个测试套件中,所以我制定了一个自定义规则:
class ResourceGrabberRule : TestRule {
override fun apply(base: Statement?, description: Description?): Statement {
return object : Statement() {
override fun evaluate() {
PowerMockito.mockStatic(ResourceGrabber::class.java)
val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)
whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
val res: Int? = invocation?.arguments?.get(0) as? Int
TestResourceGrabber.grabString(res)
}
}
}
}
}
下面是它的实现。疯狂的是,现在无论如何,每个测试都通过了:
@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Rule
@JvmField
val resourceGrabber = ResourceGrabberRule()
@Before
fun setup() {
viewModel = MyViewModel()
}
@Test
fun someTest() {
// PASSES!!!?!?!?!?!
assertEquals(2, 3)
}
}
我不确定问题出在哪里。我已经尝试从 Android Studio 和命令行构建和 运行ning 测试。我不知道是我的规则实现不正确,还是与 Powermock 连接的 JUnit 规则有问题,还是 Kotlin 注释处理有问题。测试编译并 运行 但无论测试本身内部是什么,都会通过。
我愿意接受关于这里架构的评论(我相信社区有很多),但我真的在寻找一个解释,解释为什么我写的规则通过了每一个测试。
在您的自定义 TestRule 中,您需要调用 base.evaluate()
以继续规则链 https://github.com/junit-team/junit4/wiki/rules#custom-rules
我有一个文件引用了一些静态方法:
class MyViewModel {
fun test() { }
companion object {
private val MY_STRING = ResourceGrabber.grabString(R.string.blah_blah)
}
}
在我对此文件的 JUnit 测试中,我编写了一些代码来模拟设置中的资源采集器。这编译和 运行s,下面的测试失败了,正如我所期望的那样:
@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Before
fun setup() {
PowerMockito.mockStatic(ResourceGrabber::class.java)
val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)
whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
val res: Int? = invocation?.arguments?.get(0) as? Int
TestResourceGrabber.grabString(res)
}
viewModel = MyViewModel()
}
@Test
fun someTest() {
// Fails, as expected.
assertEquals(2, 3)
}
}
这里是事情变得奇怪的地方。我最近了解了自定义 JUnit 规则,您可以使用这些规则来避免测试中出现一些重复代码。在这种情况下,我不想将我的资源采集器工作复制并粘贴到使用它的每个测试套件中,所以我制定了一个自定义规则:
class ResourceGrabberRule : TestRule {
override fun apply(base: Statement?, description: Description?): Statement {
return object : Statement() {
override fun evaluate() {
PowerMockito.mockStatic(ResourceGrabber::class.java)
val mockResourceGrabber = Mockito.mock(ResourceGrabber::class.java)
whenever(mockResourceGrabber.grabString(Mockito.anyInt())).thenAnswer { invocation ->
val res: Int? = invocation?.arguments?.get(0) as? Int
TestResourceGrabber.grabString(res)
}
}
}
}
}
下面是它的实现。疯狂的是,现在无论如何,每个测试都通过了:
@PrepareForTest(ResourceGrabber::class)
@RunWith(PowerMockRunner::class)
class MyViewModelTest {
private lateinit var viewModel: MyViewModel
@Rule
@JvmField
val resourceGrabber = ResourceGrabberRule()
@Before
fun setup() {
viewModel = MyViewModel()
}
@Test
fun someTest() {
// PASSES!!!?!?!?!?!
assertEquals(2, 3)
}
}
我不确定问题出在哪里。我已经尝试从 Android Studio 和命令行构建和 运行ning 测试。我不知道是我的规则实现不正确,还是与 Powermock 连接的 JUnit 规则有问题,还是 Kotlin 注释处理有问题。测试编译并 运行 但无论测试本身内部是什么,都会通过。
我愿意接受关于这里架构的评论(我相信社区有很多),但我真的在寻找一个解释,解释为什么我写的规则通过了每一个测试。
在您的自定义 TestRule 中,您需要调用 base.evaluate()
以继续规则链 https://github.com/junit-team/junit4/wiki/rules#custom-rules