背景
工作中經常用到單測,某對單測掌握的不好,所以趁此學習、總結一下。
主要參考: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、源碼地址
https://gitee.com/simpleha/useDemo/tree/master/junit