赞
踩
0、需要的jar
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.12</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>2.0.2-beta</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.powermock</groupId>
- <artifactId>powermock-module-junit4</artifactId>
- <version>1.7.4</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.powermock</groupId>
- <artifactId>powermock-api-mockito</artifactId>
- <version>1.7.4</version>
- <scope>test</scope>
- </dependency>

1、简单单元测试
- package test;
-
- public class ProcessDB {
-
- public String getResultOfConnectDB() {
-
- return "haha, Really went to the database";
- }
-
- }
- package test;
-
- public class BussinessService {
-
- private ProcessDB processDB;
-
- public BussinessService(ProcessDB db){
- this.processDB = db;
- }
- public String testedMehtod(){
- return processDB.getResultOfConnectDB();
- }
- }
测试类
- package test
-
- import org.junit.Assert;
- import org.junit.Test;
-
-
- public class BussinessTest {
-
-
- @Test
- public void testFuction(){
- ProcessDB db = new ProcessDB();
- BussinessService bs = new BussinessService(db);
- System.out.println(bs.testedMehtod());
- Assert.assertEquals("haha, Really went to the database", bs.testedMehtod());
- }
-
-
- }

正常的一个单元测试,测试一下正常流程,对结果进行断言。
2、mockito模拟对象
大多数时候,所测试对象依赖于一些例如数据库连接,中间件等其他远程服务,对测试造成了影响,下面用mockito模拟连接数据库的过程
- import static org.junit.Assert.*;
- import org.junit.Before;
- import org.junit.Test;
- public class BussinessTest {
-
- private ProcessDB mockDB;
- private BussinessService bs;
- @Before
- public void setUp() throws Exception {
- mockDB = mock(ProcessDB.class);
- String aa = "haha, everything is fake";
- when(mockDB.getResultOfConnectDB()).thenReturn(aa);
- bs = new BussinessService(mockDB);
- }
-
- @Test
- public void mockConnectDB(){
- assertEquals("haha, everything is fake", bs.testedMehtod());
- }
- }

这样就模拟了连接数据库的过程输出,本来真实连接数据库的时候输出“haha, Really went to the database“,但是真实连接数据库来测试比较麻烦,所以现在被模拟对象取代,输出你自己造的数据"haha, everything is fake"。
不过这一切都建立在你mock的对象是你被测试对象的属性变量,而不是在测试方法内部自己new出来的ProcessDB对象。下面看方法内部new对象,使用mockito模拟对象会怎样
3、mockito模拟方法内部new的对象
被测试类简单修改:
- package test;
-
- public class BussinessService {
-
-
- public String testedMehtod(){
- ProcessDB processDB = new ProcessDB();
- return processDB.getResultOfConnectDB();
- }
- }
测试:
- package test;
-
- import static org.mockito.Mockito.mock;
- import static org.mockito.Mockito.when;
- import static org.junit.Assert.*;
- import org.junit.Before;
- import org.junit.Test;
- public class BussinessTest {
-
- private ProcessDB mockDB;
- private BussinessService bs;
- @Before
- public void setUp() throws Exception {
- mockDB = mock(ProcessDB.class);
- String aa = "haha, everything is fake";
- when(mockDB.getResultOfConnectDB()).thenReturn(aa);
- bs = new BussinessService();
- }
-
- @Test
- public void mockConnectDB(){
- System.out.println(bs.testedMehtod());
- assertEquals("haha, everything is fake", bs.testedMehtod());
- }
- }

测试失败:
4、PowerMockito模拟方法内部创建出来的对象
- package test;
-
- public class ProcessDB {
-
- public static ProcessDB getInstance(){
- return new ProcessDB();
- }
- public String getResultOfConnectDB() {
-
- return "haha, Really went to the database";
- }
-
- }
- package test;
-
- public class BussinessService {
-
-
- public String testedMehtod(){
- ProcessDB processDB = ProcessDB.getInstance();
- return processDB.getResultOfConnectDB();
- }
- }
有时候被测试类存在这样的写法,上述mockito又不管用,使用PowerMockito来模拟
- package test;
-
- import static org.junit.Assert.assertEquals;
-
- 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;
-
- @RunWith(PowerMockRunner.class)
- @PrepareForTest(ProcessDB.class)
- public class BussinessTest {
-
- private ProcessDB mockDB;
- private BussinessService bs;
-
-
- @Test
- public void mockConnectDB(){
- PowerMockito.mockStatic(ProcessDB.class);
- mockDB = PowerMockito.mock(ProcessDB.class);
- bs = new BussinessService();
- PowerMockito.when(ProcessDB.getInstance()).thenReturn(mockDB);
- String aa = "haha, everything is fake";
- PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
- System.out.println(bs.testedMehtod());
- assertEquals("haha, everything is fake", bs.testedMehtod());
- }
- }

这样又可以测试通过,模拟了连接数据库的过程,特别注意头顶的两个注解,@RunWith(PowerMockRunner.class)
@PrepareForTest(ProcessDB.class) 。分两步:第一步模拟出假对象PowerMockito.when(ProcessDB.getInstance()).thenReturn(mockDB); ,第二步模拟假对象调用的方法PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
5、仿照上面解决3中的问题,内部直接使用new对象而不是通过静态方法getInstance()
- package test;
-
- public class BussinessService {
-
-
- public String testedMehtod(){
- ProcessDB processDB = new ProcessDB();
- return processDB.getResultOfConnectDB();
- }
- }
测试类:
- package test;
-
- import static org.junit.Assert.assertEquals;
-
- 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;
-
- @RunWith(PowerMockRunner.class)
- @PrepareForTest(ProcessDB.class)
- public class BussinessTest {
-
- private ProcessDB mockDB;
- private BussinessService bs;
-
-
- @Test
- public void mockConnectDB(){
- mockDB = PowerMockito.mock(ProcessDB.class);
- bs = new BussinessService();
- try {
- PowerMockito.whenNew(ProcessDB.class).withNoArguments().thenReturn(mockDB);
- } catch (Exception e) {
- e.printStackTrace();
- }
- String aa = "haha, everything is fake";
- PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
- System.out.println(bs.testedMehtod());
- assertEquals("haha, everything is fake", bs.testedMehtod());
- }
- }

这样看似与4相似,但是结果测试又通不过,输出的又是"haha, Really went to the database",加上PowerMockito.mockStatic(ProcessDB.class)也不管用。
6、真正解决3中的new对象的问题
其实5已经基本上实现了,经过一段时间的排查,原来问题是出在头顶上的两个注解上
- package test;
-
- import static org.junit.Assert.assertEquals;
-
- 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;
-
- @RunWith(PowerMockRunner.class)
- @PrepareForTest({ProcessDB.class, BussinessService.class})
- public class BussinessTest {
-
- private ProcessDB mockDB;
- private BussinessService bs;
-
-
- @Test
- public void mockConnectDB(){
- mockDB = PowerMockito.mock(ProcessDB.class);
- bs = new BussinessService();
- try {
- PowerMockito.whenNew(ProcessDB.class).withNoArguments().thenReturn(mockDB);
- } catch (Exception e) {
- e.printStackTrace();
- }
- String aa = "haha, everything is fake";
- PowerMockito.when(mockDB.getResultOfConnectDB()).thenReturn(aa);
- System.out.println(bs.testedMehtod());
- assertEquals("haha, everything is fake", bs.testedMehtod());
- }
- }

测试通过,一切OK
这样应该可以实现模拟对象的各种情况了,即使代码不规范,喜欢到处new依赖对象而不是将依赖对象注入服务,也可以轻松模拟对象,模拟连接远程服务,构造自己想要的数据从而完成测试自己代码逻辑。
7、流程测试的最后一步是外部依赖时的验证(例如发送到kafka等)
- package mockito;
-
- import java.util.LinkedList;
-
- public class Verify {
-
- private LinkedList k ;
- public Verify(LinkedList k){
- this.k = k;
- }
-
- public void test(){
- k.add("d");
- k.add("b");
- System.out.println(k.get(0));
- }
- }

- package mockito;
-
- import java.util.LinkedList;
- import static org.mockito.Mockito.*;
- import org.junit.Test;
-
- public class VeriryTestTest {
- @Test
- public void testt(){
- LinkedList mockedList = mock(LinkedList.class);
- when(mockedList.get(anyInt())).thenReturn("first");
- new Verify(mockedList).test();
- verify(mockedList).get(anyInt());
-
- }
- }

此测试LinkedList相当于外部依赖,最后验证依赖的某个方法是否被调用过,如果有机会调用说明流程上基本上没什么问题,验证不严谨。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。