背景
工作中经常用到单测,某对单测掌握的不好,所以趁此学习、总结一下。
主要参考:https://www.jianshu.com/p/0c2480b1709e、https://www.cnblogs.com/ljw-bim/p/9391770.html
一、不依赖外部方法的单测
1、待测试类
package com.shuimutong.demo.junit; /** * 无依赖方法 * @ClassName: NotStaticMethod * @Description:(这里用一句话描述这个类的作用) * @author: 水木桶 * @date: 2019年10月26日 上午10:37:09 * @Copyright: 2019 [水木桶] All rights reserved. */ public class NoRelayMethod { public static int ADD_NUM = 2; public static int staticAddTwo(int num) { return num + ADD_NUM; } /** * 非静态方法 * @param num * @return */ public int notStaticAddTwo(int num) { return num + ADD_NUM; } /** * 私有非静态方法 * @param num * @return */ private int privateNotStaticAddTow(int num) { return num + ADD_NUM; } }
2、单测类
package com.shuimutong.demo.junit; import java.lang.reflect.Method; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; /** * 参照1:https://www.jianshu.com/p/0c2480b1709e * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html * @ClassName: NoRelayMethodTest * @Description:(这里用一句话描述这个类的作用) * @author: 水木桶 * @date: 2019年10月26日 下午4:14:48 * @Copyright: 2019 [水木桶] All rights reserved. */ @RunWith(PowerMockRunner.class) @PrepareForTest({NoRelayMethod.class}) public class NoRelayMethodTest { @InjectMocks private NoRelayMethod noRelayMethod; //不需要mock,可以去除上面3个注解 @Test public void staticAddTwo() { int num = 3; int result = NoRelayMethod.staticAddTwo(num); Assert.assertTrue(result == (num + NoRelayMethod.ADD_NUM)); } //不需要mock,可以去除上面3个注解 @Test public void notStaticAddTwo() { int num = 1; NoRelayMethod noRelayMethod = new NoRelayMethod(); int result = noRelayMethod.notStaticAddTwo(num); Assert.assertTrue(result == (num + NoRelayMethod.ADD_NUM)); } //需要mock //mock私有方法 @Test public void privateNotStaticAddTow() throws Exception { Method method = PowerMockito.method(NoRelayMethod.class, "privateNotStaticAddTow", int.class); int num = 3; Object res = method.invoke(noRelayMethod, 3); System.out.println(res); Assert.assertEquals(num + NoRelayMethod.ADD_NUM, res); } }
3、备注
staticAddTwo和notStaticAddTwo方法不需要RunWith、PrepareForTest、InjectMocks这3个注解。
privateNotStaticAddTow涉及到私有方法,需要前面那3个注解。
二、有依赖外部静态方法的单测
1、待测试类
package com.shuimutong.demo.junit; /** * 有依赖其他静态方法 * @ClassName: RelayMethod * @Description:(这里用一句话描述这个类的作用) * @author: 水木桶 * @date: 2019年10月26日 下午3:26:01 * @Copyright: 2019 [水木桶] All rights reserved. */ public class RelayStaticMethod { public final static String DEFAULT_VAL = "defaultVal"; public final static String SIGNED = "signed"; /** * 依赖静态方法的 * @param key * @return */ public String checkAndCalc(String key) { String returnVal = null; String savedVal = RedisUtil.get(key); if(savedVal == null || savedVal.length() < 1) { returnVal = DEFAULT_VAL; } else { returnVal = savedVal + "-" + SIGNED; } return returnVal; } }
1-1、依赖外部类
package com.shuimutong.demo.junit; import java.util.UUID; public class RedisUtil { private static boolean INIT_STATE = false; public static String get(String key) { if(INIT_STATE) { return UUID.randomUUID().toString(); } else { throw new NullPointerException("资源未初始化"); } } }
2、单测类
package com.shuimutong.demo.junit; import java.util.UUID; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) //参考:https://www.jianshu.com/p/0c2480b1709e //1、如果想要对某个类的静态方法进行mock,则必须在PrepareForTest后面加上相应的类名, 比如此例的RedisUtil.class。 @PrepareForTest({RedisUtil.class}) public class RelayStaticMethodTest { /** * mock依赖的静态方法 */ @Test public void checkAndCalc() { String key1 = "jack"; String key2 = "john"; String val2 = UUID.randomUUID().toString(); //2、在对该类的某个方法进行mock之前,还必须先对整个类进行mock PowerMockito.mockStatic(RedisUtil.class); PowerMockito.when(RedisUtil.get(Mockito.eq(key1))).thenReturn(null); PowerMockito.when(RedisUtil.get(Mockito.eq(key2))).thenReturn(val2); RelayStaticMethod relayMethod = new RelayStaticMethod(); String res = relayMethod.checkAndCalc(key1); System.out.println("res:" + res); Assert.assertEquals(RelayStaticMethod.DEFAULT_VAL, res); res = relayMethod.checkAndCalc(key2); System.out.println("res:" + res); Assert.assertTrue(res.contains(RelayStaticMethod.SIGNED)); } }
2-1、运行结果
res:defaultVal
res:e76dc3b8-fcf5-42b8-9f79-1d308d137514-signed
三、有依赖外部非静态方法的单测
1、待测试类
package com.shuimutong.demo.junit; /** * 参照1:https://www.jianshu.com/p/0c2480b1709e * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html * @ClassName: UserController * @Description:(这里用一句话描述这个类的作用) * @author: 水木桶 * @date: 2019年10月26日 下午4:14:30 * @Copyright: 2019 [水木桶] All rights reserved. */ public class UserController { private UserService userService = new UserService(); public User saveUser(String name) { return userService.save(name); } }
1-1、依赖非静态类
package com.shuimutong.demo.junit; public class UserService { public User save(String name) { System.out.println("UserService--save--name:" + name); User u = new User(name); u.setId((long)(Math.random() * 1000) + 2); return u; } }
1-2、相关类User
package com.shuimutong.demo.junit; public class User { private long id; private String name; public User(String name) { this.name = name; } public User() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } @Override public String toString() { return "User [id=" + id + ", name=" + name + "]"; } }
2、单测类
package com.shuimutong.demo.junit; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; /** * 参照1:https://www.jianshu.com/p/0c2480b1709e * 参照2:https://www.cnblogs.com/ljw-bim/p/9391770.html * @ClassName: UserControllerTest * @Description:(这里用一句话描述这个类的作用) * @author: 水木桶 * @date: 2019年10月26日 下午4:13:51 * @Copyright: 2019 [水木桶] All rights reserved. */ @RunWith(PowerMockRunner.class) @PrepareForTest({UserController.class}) public class UserControllerTest { @Mock private UserService userService; @InjectMocks private UserController userController; @Test public void saveUser() { String name = "jack"; //执行userService的实际方法 PowerMockito.when(userService.save(Mockito.anyString())).thenCallRealMethod(); User returnUser = userController.saveUser(name); System.out.println("returnUser:" + returnUser); Assert.assertTrue(returnUser.getId() > 1); long id = 1L; User u1 = new User(name); u1.setId(id); System.out.println("u1:" + u1); //mock userService的方法 Mockito.when(userService.save(name)).thenReturn(u1); returnUser = userController.saveUser(name); //verify验证mock次数 Mockito.verify(userService, Mockito.times(2)).save(name); Assert.assertEquals(id, returnUser.getId()); Assert.assertEquals(u1, returnUser); System.out.println("returnUser:" + returnUser); } }
2-1、执行结果
UserService--save--name:jack
returnUser:User [id=51, name=jack]
u1:User [id=1, name=jack]
UserService--save--name:jack
returnUser:User [id=1, name=jack]
四、相关环境
1、依赖jar
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>2.10.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.2</version> <scope>test</scope> </dependency>
2、源码地址