Mockito和PowerMock用法

Mockito和PowerMock用法

一、mock測試和Mock對象

  • mock對象就是在調(diào)試期間用來作為真實對象的替代品
  • mock測試就是在測試過程中满钟,對那些不容易構(gòu)建的對象用一個虛擬對象來代替測試的方法就叫mock測試

二、Mockito和PowerMock

? PowerMock是Java開發(fā)中的一種Mock框架俯画,用于單元模塊測試拐纱。當你想要測試一個service接口,但service需要經(jīng)過防火墻訪問敦冬,防火墻不能為你打開或者你需要認證才能訪問。遇到這樣情況時唯沮,你可以在你能訪問的地方使用MockService替代脖旱,模擬實現(xiàn)獲取數(shù)據(jù)。

? PowerMock可以實現(xiàn)完成對private/static/final方法的Mock(模擬)介蛉,而Mockito可以對普通的方法進行Mock萌庆,如:public等。

三币旧、Mockito的使用

// 1践险、模擬HttpServletRequest對象,不需要依賴web容器吹菱,模擬獲得請求參數(shù)
HttpServletRequest request = mock(HttpServletRequest.class); 
when(request.getParameter("foo")).thenReturn("boo");
// 注意:mock()是Mockito的靜態(tài)方法巍虫,可以用@mock注解替換
private @mock HttpServletRequest request
// 2、Person person =mock(Person.class);
// 第一次調(diào)用返回"xiaoming"毁葱,第二次調(diào)用返回"xiaohong"
when(person.getName()).thenReturn("xiaoming").thenReturn("xiaohong"); 
when(person.getName()).thenReturn("xiaoming", "xiaohong"); 
when(person.getName()).thenReturn("xiaoming"); 
when(person.getName()).thenReturn("xiaohong");
// 3垫言、mockito模擬測試無返回值的方法
Person person =mock(Person.class);
doNothing().when(person).remove();
// 4贰剥、mockito還能對被測試的方法強行拋出異常
Person person =mock(Person.class);
doThrow(new RuntimeException()).when(person).remove();
when(person.next()).thenThrow(new RuntimeException());
// 5倾剿、//UserAppService用于參數(shù)匹配器的demo
參數(shù)匹配器
    UserApp app = new UserApp();
    app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
    app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
    when(userAppMapper.getAppSecretByAppKey(argThat(new ArgumentMatcher<String>() {
        @Override
        public boolean matches(Object argument) {
            String arg = (String) argument;
            if (arg.equals("1234567890") || arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
                return true;
            } else {
                throw new RuntimeException();
            }
        }
    }))).thenReturn(app);
// 6、Answer接口模擬根據(jù)參數(shù)返回不同結(jié)果
    when(userAppMapper.getAppSecretByAppKey(anyString())).thenAnswer(
            (InvocationOnMock invocationOnMock) -> {
                String arg = (String) invocationOnMock.getArguments()[0];
                if (null == arg || arg.equals(null)) {
                    return null;
                } else if (arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
                    UserApp app = new UserApp();
                    app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
                    app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
                    return app;
                } else {
                    return null;
                }

            });

// 7蚌成、Mock對象是能調(diào)用模擬方法前痘,調(diào)用不了它真實的方法,但是spy() 或者@spy 可以監(jiān)視一個真實的對象担忧,對它進行方法調(diào)用時它將調(diào)用真實的方法芹缔,同時也可以設(shè)定這個對象的方法讓它返回我們的期望值。同時瓶盛,我們也可以用verify進行驗證最欠。
class A {
  public void goHome() {  
      System.out.println("I say go go go!!"); 
       return true; 
   }  
 }
  //  當需要整體Mock示罗,只有少部分方法執(zhí)行真正部分時,選用這種方式 
   A mockA = Mockito.mock(A.class);   
   Mockito.doCallRealMethod().when(mockA).goHome(); 
  // 當需要整體執(zhí)行真正部分芝硬,只有少部分方法執(zhí)行mock蚜点,選用這種方式  
   A spyA = Mockito.spy(new A());   
   Mockito.when(spyA.goHome()).thenReturn(false); 

Demo演示

//目標測試類
@Service
public class UserAppService {

    @Autowired
    private UserAppMapper userAppMapper;

    /**
     * 通過appKey查詢AppSecre
     * @return
     */
    public String getAppSecretByAppKey(String appKey){
        if (StringUtils.isEmpty(appKey)) {
            return null;
        }
        UserApp userApp = userAppMapper.getAppSecretByAppKey(appKey);
        if (null == userApp) {
            return null;
        }
        return userApp.getAppSecret();
    }
}
@RunWith(SpringJUnit4ClassRunner.class)
public class UserAppServiceTest {
    @InjectMocks //創(chuàng)建一個實例,其余用@Mock(或@Spy)注解創(chuàng)建的mock將被注入到用該實例中
    private UserAppService userAppService;
    @Mock
    private UserAppMapper userAppMapper;
    @Before
    public void setUp() { MockitoAnnotations.initMocks(this);  }//初始化Mock對象
    @Test
    public void getAppSecretByAppKey3() throws Exception {
        when(userAppMapper.getAppSecretByAppKey(anyString())).thenAnswer(
                (InvocationOnMock invocationOnMock) -> {
                    String arg = (String) invocationOnMock.getArguments()[0];
                    if (null == arg || arg.equals(null)) {
                        return null;
                    } else if (arg.equals("q1w2e3r4t5y6u7i8o9p0")) {
                        UserApp app = new UserApp();
                        app.setAppKey("q1w2e3r4t5y6u7i8o9p0");
                        app.setAppSecret("q1w2e3r4t5y6u7i8o9p0");
                        return app;
                    } else {
                        return null;
                    }

                });
        assertEquals(userAppService.getAppSecretByAppKey("q1w2e3r4t5y6u7i8o9p0"), "q1w2e3r4t5y6u7i8o9p0");
        assertEquals(userAppService.getAppSecretByAppKey("123456789"), null);
        assertEquals(userAppService.getAppSecretByAppKey(null), null);
        verify(userAppMapper, only()).getAppSecretByAppKey(anyString());
    }
// 注意:verify記錄著這個模擬對象調(diào)用了什么方法拌阴,調(diào)用了多少次绍绘,never() 沒有被調(diào)用,相當于 times(0)迟赃,atLeast(N) 至少被調(diào)用 N 次陪拘,atLeastOnce() 相當于 atLeast(1),atMost(N) 最多被調(diào)用 N 次
// 參數(shù)匹配也可以為:verify(mock).someMethod(anyInt(), anyString()); 

四纤壁、PowerMock的使用

PowerMock基于Mockito開發(fā)左刽,起語法規(guī)則與Mockito一致,主要區(qū)別在于使用方面酌媒,以實現(xiàn)完成對private/static/final等方法(也支持mock的對象是在方法內(nèi)部new出來的)的Mock(模擬)悠反。具體事例如下:

1、添加依賴

<dependency>
   <groupId>org.powermock</groupId>
   <artifactId>powermock-module-junit4</artifactId>
   <version>${powermock.version}</version>
   <scope>test</scope>
   <exclusions>
      <exclusion>
         <artifactId>objenesis</artifactId>
         <groupId>org.objenesis</groupId>
      </exclusion>
   </exclusions>
</dependency>
<dependency>
   <groupId>org.powermock</groupId>
   <artifactId>powermock-api-mockito</artifactId>
   <version>${powermock.version}</version>
   <scope>test</scope>
</dependency>
//2馍佑、 PowerMock有兩個重要的注解:
      –@RunWith(PowerMockRunner.class)
      –@PrepareForTest( { YourClassWithEgStaticMethod.class })
     // 如果你的測試用例里沒有使用注解@PrepareForTest斋否,那么可以不用加注解@RunWith(PowerMockRunner.class),反之亦然拭荤。當你需要使用PowerMock強大功能(Mock靜態(tài)茵臭、final、私有方法等)的時候舅世,就需要加注解@PrepareForTest旦委。

//測試類
public class ClassUnderTest {  
    public boolean callArgumentInstance(File file) {  
        return file.exists();  
    }   
    public boolean callFinalMethod(ClassDependency refer) {  
        return refer.isAlive();  
    }  
    public boolean callStaticMethod() {  
        return ClassDependency.isExist();  
    }  
    public boolean callPrivateMethod() {  
       return ClassDependency.delete(); 
    }  
}  
//依賴類
public class ClassDependency {  
    public static boolean isExist() {   
        return false;  
    }  
    public final boolean isAlive() {  
        return false;  
    }  
    priavte final boolean delete() {  
        return false;  
    }  
}    
// 2、Mock方法內(nèi)部new出來的對象
public void testCallInternalInstance() throws Exception {  
    File file = PowerMockito.mock(File.class);  
    ClassUnderTest underTest = new ClassUnderTest();  
    PowerMockito.whenNew(File.class).withArguments("bbb").thenReturn(file);  
    PowerMockito.when(underTest.callArgumentInstance( new File("bbb"))).thenReturn(true);  
    PowerMockito.when(file.exists()).thenReturn(true); 
    Assert.assertTrue(file.exists(); 
}   
// 3雏亚、Mock普通對象的final方法
public void testCallFinalMethod() {  
    ClassDependency depencency = PowerMockito.mock(ClassDependency.class);  
    ClassUnderTest underTest = new ClassUnderTest();  
    PowerMockito.when(depencency.isAlive()).thenReturn(true);  
    Assert.assertTrue(underTest.callFinalMethod(depencency)); 
}  
// 4缨硝、Mock靜態(tài)方法
public void testCallStaticMethod() {  
    ClassUnderTest underTest = new ClassUnderTest();  
    PowerMockito.mockStatic(ClassDependency.class);  
    PowerMockito.when(ClassDependency.isExist()).thenReturn(true);  
    Assert.assertTrue(underTest.callStaticMethod());  
}
// 5、Mock私有方法
public void testCallPrivateMethod() throws Exception {  
    ClassUnderTest underTest = PowerMockito.mock(ClassUnderTest.class);  
    PowerMockito.when(underTest,"callPrivateMethod").thenCallRealMethod(); 
    Assert.assertTrue(underTest.callPrivateMethod());  
 }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末罢低,一起剝皮案震驚了整個濱河市查辩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌网持,老刑警劉巖宜岛,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異功舀,居然都是意外死亡萍倡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門辟汰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來列敲,“玉大人阱佛,你說我怎么就攤上這事〈鞫” “怎么了瘫絮?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長填硕。 經(jīng)常有香客問我麦萤,道長,這世上最難降的妖魔是什么扁眯? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任壮莹,我火速辦了婚禮,結(jié)果婚禮上姻檀,老公的妹妹穿的比我還像新娘命满。我一直安慰自己,他們只是感情好绣版,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布胶台。 她就那樣靜靜地躺著,像睡著了一般杂抽。 火紅的嫁衣襯著肌膚如雪诈唬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天缩麸,我揣著相機與錄音铸磅,去河邊找鬼。 笑死杭朱,一個胖子當著我的面吹牛阅仔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播弧械,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼八酒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了刃唐?” 一聲冷哼從身側(cè)響起羞迷,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唁桩,沒想到半個月后闭树,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耸棒,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡荒澡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了与殃。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片单山。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡碍现,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出米奸,到底是詐尸還是另有隱情昼接,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布悴晰,位于F島的核電站慢睡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏铡溪。R本人自食惡果不足惜漂辐,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望棕硫。 院中可真熱鬧髓涯,春花似錦、人聲如沸哈扮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滑肉。三九已至包各,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間靶庙,已是汗流浹背髓棋。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惶洲,地道東北人按声。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像恬吕,于是被迫代替她去往敵國和親签则。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容