最近剛剛離職,離職前1個月項目尾聲,在公司做單體測試,從模仿開始,積累了一些東西,記錄下來,留備以后不時之需;在做的時候我也在谷歌之類的搜索想深入學(xué)習(xí)下,有個感悟就是國內(nèi)的相關(guān)書籍都是比較舊的,一般都是04年左右的東西,和現(xiàn)在做的關(guān)聯(lián)性不大,可能看看也有點用,原理應(yīng)該是相同的,但是沒有實例,沒有和所用的技術(shù)相一致的api,感覺很浪費時間,谷歌上的api和stackoverflow上的提問之類的都是比較靠譜和比較貼近工作的,但又全是英語的,有一些大致能看懂,但是摳細(xì)節(jié)就不夠用了,下邊是工作中遇到的一些問題,自己做的總結(jié),可能以后某一天還會做單體測試,也可以快速撿起來。
創(chuàng)新互聯(lián)主要從事網(wǎng)站制作、成都網(wǎng)站設(shè)計、網(wǎng)頁設(shè)計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)湘陰,十余年網(wǎng)站建設(shè)經(jīng)驗,價格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
需要jar包:
javassist-3.16.1-GA.jar
mockito-all-1.9.5.jar
powermock-api-mockito-1.5.6.jar
powermock-api-support-1.5.6.jar
powermock-core-1.5.6.jar
powermock-module-junit4-1.5.6.jar
powermock-module-junit4-common-1.5.6.jar
powermock-reflect-1.5.6.jar
junit-4.10.jar
在使用mock時,首先要在測試類上加上注解@PrepareForTest({類名.class}),這里的“類名.class”是類里調(diào)用的類,需要被mock的類
當(dāng)需要mock私有方法調(diào)用的私有方法時,需要加上@RunWith(PowerMockRunner.class),其余不需要加,創(chuàng)建時也可以用new。
public調(diào)用有返回值的private方法
PowerMockito.when(對象,“私有方法名”,參數(shù)).thenReturn(期望的value);此方法要加上@RunWith(PowerMockRunner.class),此時創(chuàng)建類的對象時不能直接用new,需要用PowerMockito.Mock(類名.class);并需要將 類名.class放到類上的注解@PrepareForTest({類名.class})內(nèi);
用mock對象替換原代碼中的對象
e.g:
public class AA{
Private User u;
public void A(){
u.getName();
}
}
@PrepareForTest({User.class})
Public class test{
@Test
public void test_001(){
AA a = new AA();
User u1 = PowerMockito.Mock(User.class);
Whitebox.setInternalState(a,"u",u1);
PowerMockito.when(u1.getName()).thenReturn(value);
}
}
4.要對一個類內(nèi),方法調(diào)用的方法進(jìn)行mock
e.g:public class AA{
private User u;
private Ver v;
public void getData(){
String a = u.getName();
String b = v.getAge();
}
}
測試的過程:①.首先對整個類進(jìn)行mock
②.然后調(diào)用方法
③.接著mock調(diào)用的類
④.新對象的名字代替代碼里的
⑤.對方法進(jìn)行mock
⑥.調(diào)方法。
e.g:①.AA a = PowerMockito.mock(AA.class);
②.PowerMockito.doCallRealMethod.when(a).getData();
③.User u1 = PowerMockito.mock(User.class);
④.Whitebox.setInternalState(a,"u",u1);
⑤.PowerMockito.when(u1.getName()).thenReturn(value);
⑥.a.getData();
5.測試中測異常
PowerMockito.doThrow(new Exception()).when(對象).getName();
new Exception()是你期待的異常,getName是出異常的方法;
6.測試異常實例
e.g:public class A{
private U u = null;
public void putData(Data d){
try{
u.putData(參數(shù),參數(shù));
}catch(AccessException e){
throw new xxxxException(e,....);
}
}
}
測試類
@prepareForTest{(A.class,U.class)}
public class ATest{
@Test
public void test_001(){
Data d = new Data();
d.setName("a");
A a = PowerMockito.mock(A.class);
PowerMockito.docallRealMethod.when(a).putData(d);
U u = PowerMockito.mock(U.class);
whitebox.setInteralState(a,"u",u);
try{
PowerMockito.doThrow(new AccessException()).when(u).putData(Mockito.any(...class),Mockito.any(..class));
a.putData(d);
}catch(AccessException e){
assertTrue(e instaceof xxxException);
assertEquals(e.getException.getMessage(),"xxxxxxx");
}
}
}
mock public 方法里調(diào)用的私有方法
A a = PowerMockito.mock(A.class);
PowerMockito.doCallRealMethod().when(a).putData(); //putData()為A的方法
PowerMockito.when(a,"getName()",value.getId(),value.getName()).thenReturn("abc");// getName為私有方法,value.getId(),value.getName()為方法參數(shù)
參數(shù)要看代碼中是用的什么,如果代碼中是value.getId()的形式,測試代碼中也要是這種形式,否則就會無法返回期望值。
7、在對方法進(jìn)行mock時,要注意寫法一致
錯誤寫法:
PowerMockito.doReturn(xx).when(instance,method(args));
①、PowerMockito.doReturn(xx).when(instance).方法名(args);
②、PowerMockito.when(instance.方法名(args));.thenReturn(xx);
在mock時,方法的參數(shù)優(yōu)勢會遇到問題(造不出來),可使用Mockito.any()和mockito.eq()來解決;
e.g:Mockito.any(User.class) //參數(shù)是對象,可以用any,里面為類.class;
Mockito.eq(字段名);//參數(shù)是字符串等類型; 用eq
8、在對方法進(jìn)行mock時,方法里使用的全局成員變量始終為null(事實上在成員變量初始化時,是設(shè)置初始值了的,但是卻為null),要給成員變量在case里賦值。
使用Whitebox.setInternalState(instance,"代碼里字段名",新名字);
可以在上邊為新名字賦上值傳進(jìn)去。
9、在A類的B方法里有對同一個類的私有方法C的調(diào)用,并需要返回值。(此方法堪稱大招,對測試私有方法,并mock私有方法內(nèi)的私有方法有奇效!?。。?/p>
public void test_001(){
A a = PowerMockito.mock(A.class);
PowerMockito.when(a,"c",arg1,arg2).thenReturn("01");
Whitebox.invokeMethod(a,"c",arg1,arg2); //c是私有方法名
PowerMockito.when(a,"B",args).thencallRealMethod();
Whitebox.invokeMethod(a,"B",args);
}
10、mock A類的構(gòu)造器(有時構(gòu)造器可能有很復(fù)雜的處理),但需要造一個假的對象來使用
@RunWith(PowerMockRunner.class)
@PrepareForTest({A.class,B.class})
public class BTest{
@Test
public void test_001(){
B b = PowerMockito.Mock(B.class);
PowerMockito.doCallRealMethod().when(b).getName(id);
A a = PowerMockito.mock(A.class);
PowerMockito.whenNew(A.class).withArguments(Mockito.any(C.class),Mockito.any(D.class)).thenReturn(a);
}
}
11、在A類的B方法里new了C類(局部的),并用C對象調(diào)用了C類的方法。
mock局部對象的方法:
A a = new A();
C c = new C();
PowerMockito.whenNew(C.class).whthArguments().thenReturn(c);
c.getName();
12.mock 靜態(tài)方法
@RunWith(PowerMockRunner.class)
@PrepareForTest({A.class})
public class ATest{
@Test
public void test_static_001(){
PowerMockito.mockStatic(A.class);
PowerMockito.when(A.getName()).thenReturn("01");
}
}
13.mock 全局變量的方法2
public class A{
private User u ;
}
使用Powermockito.field(xx.class,"字段").set(對象,想賦的值);