一帆磨砺

生活所迫,一叶孤舟

0%

Mockito与PowerMock基础使用说明

写在开头

本文仅仅示范基础使用方法,仅仅提供一个快速入门的遍历,后续的高级操作还需各位自己探索。

Mockito与PowerMock基础使用说明

maven引用
1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 要求junit为4+ -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
通用基础设置
1
2
3
4
5
6
7
8
@RunWith(PowerMockRunner.class)
@PowerMockIgnore({"javax.net.ssl.*","javax.crypto.*","org.xml.*", "javax.xml.*"})
public class BasedTest {
@Test
public void baseTest() {
System.out.println("hello mockito.");
}
}

该类将作为所有测试方法的父类,因为@RunWith(PowerMockRunner.class)是使用PowerMock和Mockito的必备注解,每个测试类均需要,@PowerMockIgnore是为了解决特殊异常:

By default PowerMock loads all classes with its MockClassLoader. The classloader loads and modified all classes except:

  • system classes. They are deferred to system classloader

  • classes located in packages that are specified as ignored.

其中,javax.net.ssl.*针对网络使用,javax.crypto.*针对加密方法,org.xml.*javax.xml.*针对xml文件解析方法。

静态方法
1
2
3
4
5
6
7
8
9
public class Static {
public static String staticMethod() {
return "static";
}

public static String staticWithParam(String param) {
return param + "_";
}
}

针对上述静态方法,测试类代码为:

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
@PrepareForTest(Static.class)
public class StaticTest extends BasedTest {

@Before
public void init() {
PowerMockito.mockStatic(Static.class);
}

@Test
public void testStaticMethod() {
Mockito.when(Static.staticMethod()).thenReturn("mockito static");
Assert.assertEquals("mockito static", Static.staticMethod());
}

@Test
public void testStaticWithParam() {
// 该方式会导致所有的方法调用均通过Mockito
Mockito.when(Static.staticWithParam("test")).thenReturn("mockito static");
Mockito.when(Static.staticWithParam("static")).thenReturn("static_");
Assert.assertEquals("static_", Static.staticWithParam("static"));
Assert.assertEquals("mockito static", Static.staticWithParam("test"));
Assert.assertEquals(null, Static.staticWithParam("null"));
}

@Test
public void testStaticWithParamBySpy() {
PowerMockito.spy(Static.class);
PowerMockito.when(Static.staticWithParam("test")).thenReturn("mockito static");
Assert.assertEquals("static_", Static.staticWithParam("static"));
Assert.assertEquals("mockito static", Static.staticWithParam("test"));
}
}

针对有参静态方法,使用了spy作为特殊处理,因为使用该方法后,当调用参数为设置规则之外参数,将会调用原生方法执行,如果如同注释部分代码,规则之外参数将只会通过mock执行,有返回值的方法只会返回null。可以通过方法testStaticWithParamtestStaticWithParamBySpy进行对比。最简单明了的好处就是添加了spy后可以针对源代码debug,是可以测试具体的代码逻辑的。注意需要配合注解@PrepareForTest(Static.class)联合使用。

整体待测试项目结构与代码
1
2
3
4
5
6
7
st=>start: Start
e=>end
opc=>operation: controller
ops=>operation: service
opm=>operation: mapper

st->opc->ops->opm->e

具体代码:

Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Controller
public class TestController {
@Autowired
private TestService testService;

@RequestMapping("testMethod")
@ResponseBody
public String testMethod() {
return testService.test();
}

@RequestMapping("testMethodWithParam")
@ResponseBody
public String testMethodWithParam(Map<String, String> param) {
return testService.testWithParam(param);
}
}

Service:

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
public interface TestService {
String test();

String testWithParam(Map<String, String> param);

String testPrivateMethod(String param);
}

@Service
public class TestServiceImpl implements TestService {
@Autowired
private TestMapper testMapper;
@Override
public String test() {
return testMapper.test();
}

@Override
public String testWithParam(Map<String, String> param) {
return String.valueOf(param.size());
}

@Override
public String testPrivateMethod(String param) {
return privateMethod(param);
}

private String privateMethod(String param) {
return param + "---";
}
}

Mapper:

1
2
3
public interface TestMapper {
String test();
}
基础测试
controller
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
public class TestControllerTest extends BasedTest {
/**
* 使用注解的mock对象只会通过设置的规则,不会处理非设置条件
*/
@Mock
private TestService testService;

@Autowired
@InjectMocks
private TestController testController;

@Test
public void testTestMethod() {
Mockito.when(testService.test()).thenReturn("mockito");
Assert.assertEquals("mockito", testController.testMethod());
}

/**
* 需要设置详尽的规则,未设置的只会返回null
*/
@Test
public void testTestMethodWithParam() {
Map<String,String> test = new HashMap<>();
test.put("1","2");
PowerMockito.when(testService.testWithParam(Mockito.any())).thenReturn("others");
// 后配置规则覆盖之前规则,此处覆盖指的是优先级高,并不是替换
PowerMockito.when(testService.testWithParam(test)).thenReturn("1-2");
Map<String,String> change = new HashMap<>();
change.put("1","2");
Assert.assertEquals("1-2", testController.testMethodWithParam(change));
Map<String,String> change2 = new HashMap<>();
change2.put("1","2");
change2.put("2","3");
Assert.assertEquals("others", testController.testMethodWithParam(change2));
}

/**
* 因此此处并未使用注解注入的mock对象,因此可以设置特殊规则
* 其他非规则测试不会触发mock
* 此处并未通过controller代码,严格来算,应该属于service测试
* 此处为了对比
* 放在了controller的测试类中
* @throws Exception
*/
@Test
public void testTestMethodWithParamBySpy() throws Exception {
TestServiceImpl spy = PowerMockito.spy(new TestServiceImpl());
Map<String,String> test = new HashMap<>();
test.put("1","2");
PowerMockito.doReturn("mockito").when(spy, "testWithParam", test);
Map<String,String> change = new HashMap<>();
change.put("1","2");
Assert.assertEquals("mockito", spy.testWithParam(change));
Map<String,String> change2 = new HashMap<>();
change2.put("1","2");
change2.put("2","3");
Assert.assertEquals("2", spy.testWithParam(change2));
}
}
service
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
@PrepareForTest(TestServiceImpl.class)
public class TestServiceTest extends BasedTest {
@Mock
private TestMapper testMapper;

@Autowired
@InjectMocks
private TestServiceImpl testService;

@Test
public void testTest() {
Mockito.when(testMapper.test()).thenReturn("mockito");
Assert.assertEquals("mockito", testService.test());
}

/**
* 测试私有方法
*/
@Test
public void testPrivateMethod() throws Exception {
TestServiceImpl spy = PowerMockito.spy(new TestServiceImpl());
PowerMockito.when(spy, "privateMethod", "test").thenReturn("mockito");
Assert.assertEquals("mockito", spy.testPrivateMethod("test"));
Assert.assertEquals("test2---", spy.testPrivateMethod("test2"));
}
}

Tips:需格外注意注解@PrepareForTest(TestServiceImpl.class)

欢迎关注我的其它发布渠道