使用 PowerMock 进行单元测试

单元测试(Unit Testing)又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。如果我们写的代码依赖于某些模块对象,而单元测试过程中这些对象又很难手动创建,或者模块还没有开发完成,那么就使用一个虚拟的对象来完成单元测试,这就是所谓的 Mock。

Java 单元测试中比较流行的 Mock 测试框架有 jMockEasyMockMockito,但是这些 Mock 工具都不能 Mock staticfinalprivate 方法等,而 PowerMock 能够做到。

使用 PowerMock,首先需要使用 @RunWith(PowerMockRunner.class) 将测试用例的 Runner 改为 PowerMockRunner。如果要 Mock staticfinalprivate 等方法的时候,就需要加注解 @PrepareForTest

PowerMock 有两个版本,一个是基于 EasyMock 实现的,另一个是基于 Mockito 实现的。

下面我将以 PowerMock 的 Mockito 的版本来讲述如何使用 PowerMock。

1. 普通 Mock(Mock 参数传递的对象)

测试对象

1
2
3
4
5
public class ClassUnderTest {
public boolean callArgumentInstance(File file) {
return file.exists();
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class TestClassUnderTest {
@Test
public void testCallArgumentInstance() {
// Mock 对象,也可以使用 org.mockito.Mock 注解标记来实现
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();

// 录制 Mock 对象行为
PowerMockito.when(file.exists()).thenReturn(true);

// 验证方法行为
Assert.assertTrue(underTest.callArgumentInstance(file));
}
}

普通 Mock 不需要加 @RunWith@PrepareForTest 注解。

2. Mock 方法内部 new 出来的对象

测试对象

1
2
3
4
5
6
public class ClassUnderTest {
public boolean callInternalInstance(String path) {
File file = new File(path);
return file.exists();
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
// 在测试方法之上需要添加注解 @PrepareForTest,注解里写的类是需要 Mock 的 new 对象代码所在的类。
@PrepareForTest(ClassUnderTest.class)
public void testCallInternalInstance() throws Exception {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();

// 当以参数为 bbb 创建 File 对象的时候,返回已经 Mock 的 File 对象。
PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);

Assert.assertTrue(underTest.callInternalInstance("bbb"));
}
}

3. Mock 普通对象的 final 方法

测试对象

1
2
3
4
5
public class ClassUnderTest {
public boolean callFinalMethod(ClassDependency refer) {
return refer.isAlive();
}
}
1
2
3
4
5
6
public class ClassDependency {
public final boolean isAlive() {
// do something
return false;
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
// 在测试方法之上加注解 @PrepareForTest,注解里写的类是需要 Mock 的 final 方法所在的类。
@PrepareForTest(ClassDependency.class)
public void testCallFinalMethod() {
ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.when(depencency.isAlive()).thenReturn(true);

Assert.assertTrue(underTest.callFinalMethod(depencency));
}
}

4. Mock 静态方法。

测试对象

1
2
3
4
5
public class ClassUnderTest {
public boolean callStaticMethod() {
return ClassDependency.isExist();
}
}
1
2
3
4
5
6
public class ClassDependency {
public static boolean isExist() {
// do something
return false;
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
// 在测试方法之上加注解 @PrepareForTest,注解里写的类是需要 Mock 的 static 方法所在的类。
@PrepareForTest(ClassDependency.class)
public void testCallStaticMethod() {
ClassUnderTest underTest = new ClassUnderTest();

// 表示需要 Mock 这个类里的静态方法
PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);

Assert.assertTrue(underTest.callStaticMethod());
}
}

5. Mock 私有方法

测试对象

1
2
3
4
5
6
7
8
9
10
public class ClassUnderTest {

public boolean callPrivateMethod() {
return isExist();
}

private boolean isExist() {
return false;
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
// 在测试方法之上加注解 @PrepareForTest,注解里写的类是需要 Mock 的 private 方法所在的类。
@PrepareForTest(ClassUnderTest.class)
public void testCallPrivateMethod() throws Exception {
ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);

PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod();
PowerMockito.when(underTest, "isExist").thenReturn(true);

Assert.assertTrue(underTest.callPrivateMethod());
}
}

6. Mock JDK 中类的静态、私有方法。

测试对象

1
2
3
4
5
6
7
8
9
10
public class ClassUnderTest {

public boolean callSystemFinalMethod(String str) {
return str.isEmpty();
}

public String callSystemStaticMethod(String str) {
return System.getProperty(str);
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest
@Test
// 和 Mock 普通对象的 staticfinal 方法一样,只不过注解 @PrepareForTest 里写的类不一样
// 注解里写的类是需要调用系统方法所在的类。
@PrepareForTest(ClassUnderTest.class)
public void testCallSystemFinalMethod() {
String str = PowerMockito.mock(String.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.when(str.isEmpty()).thenReturn(false);

Assert.assertFalse(underTest.callSystemFinalMethod(str));
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallSystemStaticMethod() {
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");

Assert.assertEquals("bbb", underTest.callSystemStaticMethod("aaa"));
}
}

7. Mock 依赖类中的方法(whenNew)

测试对象

1
2
3
4
5
6
7
public class ClassUnderTest {

public boolean callDependency() {
ClassDependency classDependency = new ClassDependency();
return classDependency.isGod("hh");
}
}
1
2
3
4
5
6
public class ClassDependency {
public boolean isGod(String oh){
System.out.println(oh);
return false;
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 必须加注解 @PrepareForTest 和 @RunWith
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
// 注解里写的类是依赖类所在的类。
@PrepareForTest(ClassUnderTest.class)
public void testDependency() throws Exception {
ClassUnderTest underTest = new ClassUnderTest();
ClassDependency dependency = mock(ClassDependency.class);

whenNew(ClassDependency.class).withAnyArguments().thenReturn(dependency);

when(dependency.isGod(anyString())).thenReturn(true);
Assert.assertTrue(underTest.callDependency());
}
}

8. 完整示例代码

测试目标类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package cn.enncloud.ceres.powermock;

import java.io.File;

/**
* Created by lixiangrong on 2017/7/21.
*/
public class ClassUnderTest {

public boolean callArgumentInstance(File file) {
return file.exists();
}

public boolean callInternalInstance(String path) {
File file = new File(path);
return file.exists();
}

public boolean callFinalMethod(ClassDependency refer) {
return refer.isAlive();
}

public boolean callSystemFinalMethod(String str) {
return str.isEmpty();
}

public boolean callStaticMethod() {
return ClassDependency.isExist();
}

public String callSystemStaticMethod(String str) {
return System.getProperty(str);
}

public boolean callPrivateMethod() {
return isExist();
}

public boolean callVoidPrivateMethod(){
testVoid();
return true;
}

private boolean isExist() {
// do something
return false;
}

private void testVoid(){
System.out.println("do nothing");
}

public boolean callDependency() {
ClassDependency classDependency = new ClassDependency();
return classDependency.isGod("hh");
}
}

依赖类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package cn.enncloud.ceres.powermock;

/**
* Created by lixiangrong on 2017/7/21.
*/
public class ClassDependency {

public static boolean isExist() {
// do something
return false;
}

public final boolean isAlive() {
// do something
return false;
}

public boolean isGod(String oh){
System.out.println(oh);
return false;
}
}

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package cn.enncloud.ceres.powermock.test;

import cn.enncloud.ceres.powermock.ClassDependency;
import cn.enncloud.ceres.powermock.ClassUnderTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import java.io.File;

/**
* Created by lixiangrong on 2017/7/21.
*/
@RunWith(PowerMockRunner.class)
public class TestClassUnderTest {
@Test
public void testCallArgumentInstance() {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.when(file.exists()).thenReturn(true);

Assert.assertTrue(underTest.callArgumentInstance(file));
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallInternalInstance() throws Exception {
File file = PowerMockito.mock(File.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);

Assert.assertTrue(underTest.callInternalInstance("bbb"));
}

@Test
@PrepareForTest(ClassDependency.class)
public void testCallFinalMethod() {
ClassDependency depencency = PowerMockito.mock(ClassDependency.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.when(depencency.isAlive()).thenReturn(true);

Assert.assertTrue(underTest.callFinalMethod(depencency));
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallSystemFinalMethod() {
String str = PowerMockito.mock(String.class);
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.when(str.isEmpty()).thenReturn(false);

Assert.assertFalse(underTest.callSystemFinalMethod(str));
}

@Test
@PrepareForTest(ClassDependency.class)
public void testCallStaticMethod() {
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.mockStatic(ClassDependency.class);
PowerMockito.when(ClassDependency.isExist()).thenReturn(true);

Assert.assertTrue(underTest.callStaticMethod());
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallSystemStaticMethod() {
ClassUnderTest underTest = new ClassUnderTest();

PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getProperty("aaa")).thenReturn("bbb");

Assert.assertEquals("bbb", underTest.callSystemStaticMethod("aaa"));
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallPrivateMethod() throws Exception {
ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);

PowerMockito.when(underTest.callPrivateMethod()).thenCallRealMethod();
PowerMockito.when(underTest, "isExist").thenReturn(true);

Assert.assertTrue(underTest.callPrivateMethod());
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testCallVoidPrivateMethod() throws Exception {
ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);

PowerMockito.when(underTest.callVoidPrivateMethod()).thenCallRealMethod();
PowerMockito.doNothing().when(underTest, "testVoid");

Assert.assertTrue(underTest.callVoidPrivateMethod());
}

@Test
@PrepareForTest(ClassUnderTest.class)
public void testDependency() throws Exception {
ClassUnderTest underTest = new ClassUnderTest();
ClassDependency dependency = mock(ClassDependency.class);

// @PrepareForTest(ClassUnderTest.class)
whenNew(ClassDependency.class).withAnyArguments().thenReturn(dependency);

when(dependency.isGod(anyString())).thenReturn(true);
Assert.assertTrue(underTest.callDependency());
}
}

9. Mock 与 Spy

Mock 不是真实的对象,它只是用类型的 class 创建了一个虚拟对象,并可以设置对象行为
Spy 是一个真实的对象,但它可以设置对象行为


欣赏此文?求鼓励,求支持!
显示 Disqus 评论
0%