Android 单元测试之PowerMock

1. 介绍

之前学过了 Mockito框架 Android单元测试之 Mockito,它是Mock的一种测试框架,除了Mockito,Mock框架还有 EasyMock、jMock等。

但是这些部分的Mock框架都有一个缺点:不能Mock 静态、构造、私有、final的方法,这是因为测试架构设计良好的代码, 一般不需要这些功能,但是如果在老代码上新增单元测试时,就不得不面临这些问题了。

而PowerMock正是解决这样的问题而诞生,目前,PowerMock仅支持Mockito和EasyMock两种框架。

2. 使用

2.0 导入

在 build.gradle中导入:

    testImplementation "org.powermock:powermock-module-junit4:2.0.4"
    testImplementation "org.powermock:powermock-module-junit4-rule:2.0.4"
    testImplementation "org.powermock:powermock-api-mockito2:2.0.4"
    testImplementation "org.powermock:powermock-classloading-xstream:2.0.4"

与Mockito不同,在测试类上的 @RunWith() 需要进行修改,修改成:

@RunWith(PowerMockRunner.class)

其次,在测试类需要使用到 @PrepareForTest()注解,来达到Mock final、构造函数、static、私有方法所在的类的目的。
该注解即可写在方法上,也可以以全局的方式写在类上。

下面的例子都借鉴于:PowerMock框架讲解及使用

2.1 Mock普通方法

普通的mock就等于Mokito的用法一样。

来看看下面这个类:

class PowerMockClass {
     
    public fun isFileExists(file: File): Boolean {
     
        return file.exists()
    }
}

建立测试类:

class PowerMockClassTest {
     
    @Test
    fun isFileExists() {
     
        // Mock 一个 File对象
        val file = PowerMockito.mock(File::class.java)

        // 创建当前类
        val powerMockitoClass = PowerMockClass()

        // 当Mock对象被调用了 exists() 方法,则返回False
        PowerMockito.`when`(file.exists()).thenReturn(false)

        // 进行断言
        assertFalse(file.exists())
    }

}

对于这种Mock普通对象进行测试来说,不需要使用 @RunWith还有 @PrepareForTest()

2.2 Mock 静态方法

我们创建一个 static的方法:

object PowerMockClass {
     
    @JvmStatic
    public fun isFileExists(): Boolean {
     
        return false
    }
}

创建测试类,需要使用 mockStatic(),里面装入的是我们要测试静态方法所在的类,测试类如下:

@RunWith(PowerMockRunner::class)
@PrepareForTest(PowerMockClass::class)
class PowerMockClassTest {
     

    @Test
    fun isFileExists() {
     
        // mockStatic 来Mock静态方法所在的类
        PowerMockito.mockStatic(PowerMockClass::class.java)

        // 当Mock对象被调用了 exists() 方法,则返回True
        PowerMockito.`when`(PowerMockClass.isFileExists()).thenReturn(true)

        // 进行断言
        assertTrue(PowerMockClass.isFileExists())
    }

}

注意:

  • 方法需要被 @JvmStaic修饰,这是因为伴生方法虽然看似静态,但其在JVM的运作还是使用普通的对象来的,所以需要通过 JvmStaic声明为真正的静态方法。
  • 所在类需要声明为obejct,因为 mockStatic里的类需要是静态的。

2.3 Mock final方法

final方法还是蛮好操作的,没有什么限制,来看看实现类:

class PowerMockClass {
     
    public final fun isFileExists(): Boolean {
     
        return false
    }
}

测试类如下:

@RunWith(PowerMockRunner::class)
@PrepareForTest(PowerMockClass::class)
class PowerMockClassTest {
     

    @Test
    fun isFileExists() {
     
        //  mock 一个 final方法所在的类的对象
        val pmc = PowerMockito.mock(PowerMockClass::class.java)

        // 当Mock对象被调用了 exists() 方法,则返回True
        PowerMockito.`when`(pmc.isFileExists()).thenReturn(true)

        // 进行断言
        assertTrue(pmc.isFileExists())
    }

}

2.4 Mock private方法

实现类:

class PowerMockClass {
     
    private fun isFileExists(): Boolean {
     
        return false
    }
}

测试类比较简单:

@RunWith(PowerMockRunner::class)
@PrepareForTest(PowerMockClass::class)
class PowerMockClassTest {
     
    @Test
    fun isFileExists() {
     
        //  mock 一个 private方法所在的类的对象
        val pmc = PowerMockito.mock(PowerMockClass::class.java)

        // 当Mock对象被调用了 exists() 方法,则返回True
        PowerMockito.doReturn(true).`when`(pmc, "isFileExists")
    }
}

可以看到基本和上面基本没差别,但是由于我们不能直接调用 private方法,所以不好做断言,这个时候我们可以加一个包装方法:

class PowerMockClass {
     

    public fun isPubFileExists(): Boolean {
     
        return isFileExists()
    }
    ..
}

在测试类中调用:

@RunWith(PowerMockRunner::class)
@PrepareForTest(PowerMockClass::class)
class PowerMockClassTest {
     
    @Test
    fun isFileExists() {
     
        //  mock 一个 final方法所在的类的对象
        val pmc = PowerMockito.mock(PowerMockClass::class.java)

        // 当Mock对象被调用了 exists() 方法,则返回True
        PowerMockito.`when`(pmc.isPubFileExists()).thenCallRealMethod()
        PowerMockito.`when`<Any>(pmc, "isFileExists").thenReturn(true)
        assertTrue(pmc.isPubFileExists())

    }
}

但是这样会动到实现类的代码,所以应该可以用别的方式,比如 反射。

3. 小结

PowerMock可以帮助Mocktio去Mock一些private、final、静态的方法,相较于Mockito,效率会更高一些。

你可能感兴趣的:(自动化测试)