1.針對(duì)方法打樁
1.1 打樁類的public static方法
測(cè)試用例中如果需要對(duì)public靜態(tài)方法的打樁,針對(duì)測(cè)試類增加注解@RunWith(PowerMockRunner.class)同時(shí)針對(duì)靜態(tài)方法所在的類增加注解@PrepareForTest({StaticMethod.class}),接著在測(cè)試用例調(diào)用方法之前增加
PowerMockito.mockStatic(StaticMethod.class);
PowerMockito.when(StaticMethod.getJavaVersion()).thenReturn(“1.8.0_92”); 或者用寫法
PowerMockito.doReturn(“1.8.0_92”).when(StaticMethod.class, “getJavaVersion”);
另外對(duì)PowerMockito的調(diào)用最好在產(chǎn)品類ProductClass對(duì)象new之前進(jìn)行,這樣保障一切模擬數(shù)據(jù)就緒后再進(jìn)行產(chǎn)品類的測(cè)試,保證測(cè)試用例一次性成功編寫的幾率。
import junit.framework.TestCase;
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({StaticMethod.class})
public class ProductClassTest extends TestCase {
public void test_getCustomNameByVersion() {
PowerMockito.mockStatic(StaticMethod.class);
PowerMockito.when(StaticMethod.getJavaVersion()).thenReturn("1.8.0_92");
ProductClass product = new ProductClass();
assertEquals("18VersionSeries", product.getCustomNameByVersion());
}
}
ProductClassTest.java
public class ProductClass {
public String getCustomNameByVersion() {
String javaVersion = StaticMethod.getJavaVersion();
if(javaVersion.split("_")[0].contains("1.8")) {
return "18VersionSeries";
}
else {
return "OTHER";
}
}
}
ProductClass.java產(chǎn)品代碼調(diào)用其他類的靜態(tài)方法
public class StaticMethod {
public static String getJavaVersion() {
throw new RuntimeException();
}
}
1.2 打樁類的private static方法
針對(duì)StaticMethod類中的private static方法打樁的時(shí)候,外部調(diào)用StaticMethod類的public方法仍然保持實(shí)際代碼的調(diào)用,因此在模擬private static方法之前,增加一行
PowerMockito.spy(StaticMethod.class);或者
PowerMockito.when(StaticMethod.getJavaVersion()).thenCallRealMethod();
以此保證除了具體的某個(gè)方法打樁,其他的方法保持照舊。另外,針對(duì)private方法,因?yàn)檎J菬o法直接訪問的,因此需要使用
下面的形式進(jìn)行調(diào)用。這里要注意一個(gè)事情,doReturn when 和 when thenReturn的差異,后者是雖然做了打樁但是實(shí)際的代碼還是會(huì)走一遍。
PowerMockito.doReturn(true).when(StaticMethod.class, “isProduct”);
import junit.framework.TestCase;
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({StaticMethod.class})
public class ProductClassTest extends TestCase {
public void test_getCustomNameByVersion_product() throws Exception {
PowerMockito.mockStatic(StaticMethod.class);
PowerMockito.spy(StaticMethod.class);
PowerMockito.doReturn(true).when(StaticMethod.class, "isProduct");
ProductClass product = new ProductClass();
assertEquals("18VersionSeries", product.getCustomNameByVersion());
}
}
ProductClassTest.java測(cè)試用例
public class StaticMethod {
public static String getJavaVersion() {
if (isProduct()) {
System.out.println("getJavaVersion()::product");
return System.getProperty("java.version");
}
System.out.println("getJavaVersion()::test");
throw new RuntimeException();
}
private static boolean isProduct() {
if (System.getenv().containsKey("isProduct=false")) {
System.out.println("isProduct()::false");
return false;
} else {
System.out.println("isProduct()::true");
return true;
}
}
}
StaticMethod.java
public class ProductClass {
public String getCustomNameByVersion() {
String javaVersion = StaticMethod.getJavaVersion();
if(javaVersion.split("_")[0].contains("1.8")) {
return "18VersionSeries";
}
else {
return "OTHER";
}
}
}
ProductClass.java
1.3 打樁類的public方法實(shí)現(xiàn)部分中使用的new對(duì)象
如果要對(duì) StudentHandler.java的new對(duì)象進(jìn)行mock,那么需要把StudentHandler對(duì)象所在的類StudentMng放到 @PrepareForTest({StudentMng.class})
需要特別注意,在PrepareForTest中放的類在統(tǒng)計(jì)代碼覆蓋率的時(shí)候,覆蓋率是0。如果要針對(duì)該類進(jìn)行代碼測(cè)試覆蓋,那需要以其他的方式進(jìn)行模擬測(cè)試。
1 package training;
2
3 import junit.framework.TestCase;
4 import org.junit.runner.RunWith;
5 import org.powermock.api.mockito.PowerMockito;
6 import org.powermock.core.classloader.annotations.PrepareForTest;
7 import org.powermock.modules.junit4.PowerMockRunner;
8
9
10 import java.util.ArrayList;
11 import java.util.List;
12 @RunWith(PowerMockRunner.class)
13 @PrepareForTest({StudentMng.class})
14 public class StudentMngTest extends TestCase {
15
16
17 public void test_getSpecifiedStudents() throws Exception {
18 StudentHandler handler = PowerMockito.mock(StudentHandler.class);
19 PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
20 PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler);
21 StudentMng mng = new StudentMng();
22 assertEquals(1, mng.getSpecifiedStudents(10).size());
23 }
24
25 private List<Student> mockStudents() {
26 List<Student> students = new ArrayList<>();
27 Student stu = new Student();
28 stu.setScore(new Score(80, 11));
29 students.add(stu);
30 return students;
31 }
32 }
StudentMngTest.java
1 package training;
2
3 import java.util.List;
4
5 public class StudentHandler {
6 public StudentHandler() {
7 System.out.println("invoke StudentHandler()");
8 throw new RuntimeException();
9 }
10 public List<Student> getAllStudents() {
11 System.out.println("invoke getAllStudents");
12 throw new RuntimeException();
13 }
14 }
StudentHandler.java 是一個(gè)不方便直接new的類
1 package training;
2
3 public class Student {
4 private String sno;
5 private String name;
6 private Score score = new Score(100, 1000);
7
8 public String getName() {
9 System.out.println("invoke getName");
10 return name;
11 }
12
13 public void setName(String name) {
14 System.out.println("invoke setName");
15 this.name = name;
16 }
17
18 public String getSno() {
19 System.out.println("invoke getSno");
20 return sno;
21 }
22
23 public void setSno(String sno) {
24 System.out.println("invoke setSno");
25 this.sno = sno;
26 }
27
28 public void setScore(Score score) {
29 System.out.println("invoke setScore");
30 this.score = score;
31 }
32
33 public Score getScore() {
34 System.out.println("invoke getScore");
35 return score;
36 }
37
38 public String getScoreRecord(int delta) {
39 System.out.println("invoke getScoreRecord");
40 return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
41 }
42 }
Student.java
1 package training;
2
3 public class Score {
4 private int value;
5 private int level;
6
7 public Score(int value, int level) {
8 this.value = value;
9 this.level = level;
10 }
11
12 public int getLevel() {
13 System.out.println("invoke getLevel");
14 return level;
15 }
16
17 public void setLevel(int level) {
18 System.out.println("invoke setLevel");
19 this.level = level;
20 }
21
22 public int getValue() {
23 System.out.println("invoke getValue");
24 return value;
25 }
26
27 public void setValue(int value) {
28 System.out.println("invoke setValue");
29 this.value = value;
30 }
31 }
Score.java
1.4打樁類的public方法
2種方式,方式一:PowerMockito.mock方式,對(duì)應(yīng)StudentTest.java中的test_mock_public_method_powermock()測(cè)試用例
方式二:函數(shù)復(fù)寫override方式,對(duì)應(yīng)StudentTest.java中的test_mock_public_method_override()測(cè)試用例
兩種方式比較,方式一代碼看起來簡(jiǎn)潔。 方式二 測(cè)試用例運(yùn)行時(shí)間效率很高。
1 package training;
2
3 import junit.framework.TestCase;
4 import org.powermock.api.mockito.PowerMockito;
5
6 public class StudentTest extends TestCase {
7 public void test_mock_public_method_powermock()
8 {
9 Student stu = PowerMockito.mock(Student.class);
10 PowerMockito.when(stu.getName()).thenReturn("test_name");
11 PowerMockito.when(stu.getNewName()).thenCallRealMethod();
12 assertEquals("new_test_name", stu.getNewName());
13 }
14
15 public void test_mock_public_method_override()
16 {
17 Student stu = new Student() {
18 @Override
19 public String getName() {
20 return "test_name";
21 }
22 };
23 assertEquals("new_test_name", stu.getNewName());
24 }
25 }
StudentTest.java
1 package training;
2
3 public class Student {
4 private String name;
5
6
7 public String getName() {
8 System.out.println("invoke getName");
9 throw new RuntimeException();
10 // return name;
11 }
12
13 public String getNewName() {
14 System.out.println("invoke getNewName");
15 return "new_" + getName();
16 }
17
18 }
Student.java
1.5 打樁類的private方法
Student.java類中g(shù)etName方法為private的,因此需要使用PowerMockito.when(stu, “getName”).thenReturn(“test_name”); 方式進(jìn)行mock。
被模擬的Student類需要在測(cè)試用例test類的開頭增加以下兩行。
@RunWith(PowerMockRunner.class)
@PrepareForTest({Student.class})
1 package training;
2
3 import junit.framework.TestCase;
4 import org.junit.runner.RunWith;
5 import org.powermock.api.mockito.PowerMockito;
6 import org.powermock.core.classloader.annotations.PrepareForTest;
7 import org.powermock.modules.junit4.PowerMockRunner;
8
9 @RunWith(PowerMockRunner.class)
10 @PrepareForTest({Student.class})
11 public class StudentTest extends TestCase {
12 public void test_mock_public_method_powermock()
13 {
14 Student stu = PowerMockito.mock(Student.class);
15 try {
16 PowerMockito.when(stu, "getName").thenReturn("test_name");
17 } catch (Exception e) {
18 e.printStackTrace();
19 }
20 PowerMockito.when(stu.getNewName()).thenCallRealMethod();
21 assertEquals("new_test_name", stu.getNewName());
22 }
23
24 }
StudentTest.java
1 package training;
2
3 public class Student {
4 private String sno;
5 private String name;
6 private Score score = new Score(100, 1000);
7
8 private String getName() {
9 System.out.println("invoke getName");
10 throw new RuntimeException();
11 // return name;
12 }
13
14 public String getNewName() {
15 System.out.println("invoke getNewName");
16 return "new_" + getName();
17 }
18
19 public void setName(String name) {
20 System.out.println("invoke setName");
21 this.name = name;
22 }
23
24 public String getSno() {
25 System.out.println("invoke getSno");
26 return sno;
27 }
28
29 public void setSno(String sno) {
30 System.out.println("invoke setSno");
31 this.sno = sno;
32 }
33
34 public void setScore(Score score) {
35 System.out.println("invoke setScore");
36 this.score = score;
37 }
38
39 public Score getScore() {
40 System.out.println("invoke getScore");
41 return score;
42 }
43
44 public String getScoreRecord(int delta) {
45 System.out.println("invoke getScoreRecord");
46 return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
47 }
48 }
Student.java
2.針對(duì)變量打樁
2.1 打樁類的private成員變量
方法一: Whitebox
來源StudentMngTest.java,關(guān)鍵模擬代碼如下,Whitebox.setInternalState(mng, “handler”, handler);打樁設(shè)置對(duì)象的私有成員變量。
PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();控制調(diào)用實(shí)際的方法。
StudentMng mng = PowerMockito.mock(StudentMng.class); 控制StudentMng對(duì)象的初始化過程,保證在對(duì)象初始化的時(shí)候不去做StudentHandler成員變量的初始化。
public void test_getSpecifiedStudents() {
StudentHandler handler = PowerMockito.mock(StudentHandler.class);
PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
StudentMng mng = PowerMockito.mock(StudentMng.class);
Whitebox.setInternalState(mng, “handler”, handler);
PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();
assertEquals(1, mng.getSpecifiedStudents(10).size());
}
package training;
import junit.framework.TestCase;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.reflect.Whitebox;
import java.util.ArrayList;
import java.util.List;
public class StudentMngTest extends TestCase {
public void test_getSpecifiedStudents() {
StudentHandler handler = PowerMockito.mock(StudentHandler.class);
PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
StudentMng mng = PowerMockito.mock(StudentMng.class);
Whitebox.setInternalState(mng, "handler", handler);
PowerMockito.when(mng.getSpecifiedStudents(10)).thenCallRealMethod();
assertEquals(1, mng.getSpecifiedStudents(10).size());
}
private List<Student> mockStudents() {
List<Student> students = new ArrayList<>();
Student stu = new Student();
stu.setScore(new Score(80, 11));
students.add(stu);
return students;
}
}
StudentMngTest.java 打樁后 連初始化StudentMng對(duì)象的時(shí)候都模擬完成。
package training;
import java.util.List;
public class StudentHandler {
public StudentHandler() {
System.out.println("invoke StudentHandler()");
// throw new RuntimeException();
}
public List<Student> getAllStudents() {
System.out.println("invoke getAllStudents");
throw new RuntimeException();
}
}
StudentHandler.java
package training;
public class Student {
private String sno;
private String name;
private Score score = new Score(100, 1000);
public String getName() {
System.out.println("invoke getName");
return name;
}
public void setName(String name) {
System.out.println("invoke setName");
this.name = name;
}
public String getSno() {
System.out.println("invoke getSno");
return sno;
}
public void setSno(String sno) {
System.out.println("invoke setSno");
this.sno = sno;
}
public void setScore(Score score) {
System.out.println("invoke setScore");
this.score = score;
}
public Score getScore() {
System.out.println("invoke getScore");
return score;
}
public String getScoreRecord(int delta) {
System.out.println("invoke getScoreRecord");
return String.format("sno:%s,name:%s,value:%d,level:%d", sno, name, score.getValue() + delta, score.getLevel());
}
}
Student.java
package training;
public class Score {
private int value;
private int level;
public Score(int value, int level) {
this.value = value;
this.level = level;
}
public int getLevel() {
System.out.println("invoke getLevel");
return level;
}
public void setLevel(int level) {
System.out.println("invoke setLevel");
this.level = level;
}
public int getValue() {
System.out.println("invoke getValue");
return value;
}
public void setValue(int value) {
System.out.println("invoke setValue");
this.value = value;
}
}
Score.java
方法二(更加通用):用以下方式修改屬性的訪問權(quán)限,另外 @PrepareForTest({StudentMng.class}) 和 PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler); 同時(shí)來達(dá)到mock new對(duì)象的目的。
Field handlerField = mng.getClass().getDeclaredField(“handler”);
handlerField.setAccessible(true);
handlerField.set(mng, handler);
1 package training;
2
3 import junit.framework.TestCase;
4 import org.junit.runner.RunWith;
5 import org.powermock.api.mockito.PowerMockito;
6 import org.powermock.core.classloader.annotations.PrepareForTest;
7 import org.powermock.modules.junit4.PowerMockRunner;
8
9 import java.lang.reflect.Field;
10 import java.util.ArrayList;
11 import java.util.List;
12
13 @RunWith(PowerMockRunner.class)
14 @PrepareForTest({StudentMng.class})
15 public class StudentMngTest extends TestCase {
16 public void test_getSpecifiedStudents() throws Exception {
17 StudentHandler handler = PowerMockito.mock(StudentHandler.class);
18 PowerMockito.when(handler.getAllStudents()).thenReturn(mockStudents());
19 PowerMockito.whenNew(StudentHandler.class).withNoArguments().thenReturn(handler);
20 StudentMng mng = new StudentMng();
21 Field handlerField = mng.getClass().getDeclaredField("handler");
22 handlerField.setAccessible(true);
23 handlerField.set(mng, handler);
24 assertEquals(1, mng.getSpecifiedStudents(10).size());
25 }
26
27 private List<Student> mockStudents() {
28 List<Student> students = new ArrayList<>();
29 Student stu = new Student();
30 stu.setScore(new Score(80, 11));
31 students.add(stu);
32 return students;
33 }
34 }
StudentMngTest.java
2.2 打樁類的public static變量或者private static變量
針對(duì)此類情況,建議對(duì)static變量賦值的部分進(jìn)行mock模擬,以此來達(dá)到模擬變量值得目的。
3.測(cè)試用例執(zhí)行效率簡(jiǎn)單說明
override方式模擬打樁方式的執(zhí)行測(cè)試用例時(shí)間消耗
< 不帶@RunWith(PowerMockRunner.class)和@PrepareForTest({StudentMng.class}) 方式的執(zhí)行測(cè)試用例時(shí)間消耗
< 只帶@RunWith(PowerMockRunner.class)方式的的執(zhí)行測(cè)試用例時(shí)間消耗
< 都帶@RunWith(PowerMockRunner.class)和@PrepareForTest({StudentMng.class}) 方式的的執(zhí)行測(cè)試用例時(shí)間消耗
關(guān)于代碼覆蓋率:在PrepareForTest中放的類在統(tǒng)計(jì)代碼覆蓋率的時(shí)候,覆蓋率是0。如果要針對(duì)該類進(jìn)行代碼測(cè)試覆蓋,
那需要以其他的方式進(jìn)行模擬測(cè)試。
關(guān)于編寫產(chǎn)品代碼:建議在編寫產(chǎn)品代碼的時(shí)候,盡量按照對(duì)象注入方式,同時(shí)減少靜態(tài)方法的實(shí)現(xiàn)方式,文章來源:http://www.zghlxwxcb.cn/news/detail-821535.html
以此也能增加代碼的靈活性,同時(shí)在給編寫測(cè)試用例也能帶來較大的便利。文章來源地址http://www.zghlxwxcb.cn/news/detail-821535.html
到了這里,關(guān)于【Java】使用PowerMockito mock static方法/new對(duì)象/mock對(duì)象的public或private方法的簡(jiǎn)單示例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!