junit單體測試(PowerMockito)一

    最近剛剛離職,離職前1個月項目尾聲,在公司做單體測試,從模仿開始,積累了一些東西,記錄下來,留備以後不時之需;在做的時候我也在谷歌之類的搜索想深入學習下,有個感悟就是國內的相關書籍都是比較舊的,一般都是04年左右的東西,和現在做的關聯性不大,可能看看也有點用,原理應該是相同的,但是沒有實例,沒有和所用的技術相一致的api,感覺很浪費時間,谷歌上的api和stackoverflow上的提問之類的都是比較靠譜和比較貼近工作的,但又全是英語的,有一些大致能看懂,但是摳細節就不夠用了,下邊是工作中遇到的一些問題,自己做的總結,可能以後某一天還會做單體測試,也可以快速撿起來。

    需要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”是類裏調用的類,需要被mock的類

  1. 當需要mock私有方法調用的私有方法時,需要加上@RunWith(PowerMockRunner.class),其餘不需要加,創建時也可以用new。

  2. public調用有返回值的private方法

    PowerMockito.when(對象,“私有方法名”,參數).thenReturn(期望的value);此方法要加上@RunWith(PowerMockRunner.class),此時創建類的對象時不能直接用new,需要用PowerMockito.Mock(類名.class);並需要將 類名.class放到類上的註解@PrepareForTest({類名.class})內;

  3. 用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.要對一個類內,方法調用的方法進行mock

   e.g:public class AA{

        private User u;

        private Ver v;

        public void getData(){

            String a = u.getName();

            String b = v.getAge();

        }

   }

   測試的過程:①.首先對整個類進行mock

               ②.然後調用方法

               ③.接着mock調用的類

               ④.新對象的名字代替代碼裏的

               ⑤.對方法進行mock 

               ⑥.調方法。 

   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(參數,參數);

        }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 方法裏調用的私有方法

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()爲方法參數

參數要看代碼中是用的什麼,如果代碼中是value.getId()的形式,測試代碼中也要是這種形式,否則就會無法返回期望值。


7、在對方法進行mock時,要注意寫法一致

錯誤寫法:

PowerMockito.doReturn(xx).when(instance,method(args));

①、PowerMockito.doReturn(xx).when(instance).方法名(args);

②、PowerMockito.when(instance.方法名(args));.thenReturn(xx);

在mock時,方法的參數優勢會遇到問題(造不出來),可使用Mockito.any()和mockito.eq()來解決;

e.g:Mockito.any(User.class) //參數是對象,可以用any,裏面爲類.class;

    Mockito.eq(字段名);//參數是字符串等類型; 用eq


8、在對方法進行mock時,方法裏使用的全局成員變量始終爲null(事實上在成員變量初始化時,是設置初始值了的,但是卻爲null),要給成員變量在case裏賦值。

使用Whitebox.setInternalState(instance,"代碼裏字段名",新名字);

可以在上邊爲新名字賦上值傳進去。


9、在A類的B方法裏有對同一個類的私有方法C的調用,並需要返回值。(此方法堪稱大招,對測試私有方法,並mock私有方法內的私有方法有奇效!!!)

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類的構造器(有時構造器可能有很複雜的處理),但需要造一個假的對象來使用

@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對象調用了C類的方法。

mock局部對象的方法:

    A a = new A();

    C c = new C();

    PowerMockito.whenNew(C.class).whthArguments().thenReturn(c);

    c.getName();


12.mock 靜態方法

@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(對象,想賦的值);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章