日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

powermockito教程_Mockito与PowerMock的使用基础教程

發布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 powermockito教程_Mockito与PowerMock的使用基础教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、Mockito與PowerMock簡述

Mockito與PowerMock都是Java流行的一種Mock框架,使用Mock技術能讓我們隔離外部依賴以便對我們自己的業務邏輯代碼進行單元測試,在編寫單元測試時,不需要再進行繁瑣的初始化工作,在需要調用某一個接口時,直接模擬一個假方法,并任意指定方法的返回值。

Mockito的工作原理是通過創建依賴對象的proxy,所有的調用先經過proxy對象,proxy對象攔截了所有的請求再根據預設的返回值進行處理。PowerMock則在Mockito原有的基礎上做了擴展,通過修改類字節碼并使用自定義ClassLoader加載運行的方式來實現mock靜態方法、final方法、private方法、系統類的功能。

從兩者的項目結構中就可以看出,PowerMock直接依賴于Mockito,所以如果項目中已經導入了PowerMock包就不需要再單獨導入Mockito包,如果兩者同時導入還要小心PowerMock和Mockito不同版本之間的兼容問題:

Mockito包依賴:

org.mockito

mockito-core

2.23.0

test

PowerMock包依賴:

org.powermock

powermock-module-junit4

2.0.0-RC.3

test

org.powermock

powermock-api-mockito2

2.0.0-RC.3

test

二、Mockito的使用

Mockito一般通過創建mock或spy對象,并制定具體返回規則來實現模擬的功能,在調用完成后還可以進行方法調用驗證以檢驗程序邏輯是否正確。mock和spy對象的區別是mock對象對于未指定處理規則的調用會按方法返回值類型返回該類型的默認值(如int、long則返回0,boolean則返回false,對象則返回null,void則什么都不做),而spy對象在未指定處理規則時則會直接調用真實方法。

以下3個類是我們的項目中需要用到的一些業務類:

//實體類

public class Node {

private int num;

private String name;

//以下忽略所有構造方法和get、set方法

}

//本地負責實現具體業務的業務類

public class LocalServiceImpl implements ILocalService {

//外部依賴

@Autowired

private IRemoteService remoteService;

//具體業務處理方法

@Override

public Node getRemoteNode(int num) {

return remoteService.getRemoteNode(num);

}

//以下忽略其他業務調用方法,在后面例子中補充

}

//外部依賴業務類,由其他人實現,可能我們的業務類寫好了別人還沒寫好

public class RemoteServiceImpl implements IRemoteService {

//外部類提供的一些業務方法

@Override

public Node getRemoteNode(int num) {

return new Node(num, "Node from remote service");

}

//其他業務方法在后面例子中補充

}

下面是Mockito具體使用的一些示例:

mock外部依賴對象,并注入到我們的業務類中,以便在單元測試中進行模擬調用:

@RunWith(MockitoJUnitRunner.class) //讓測試運行于Mockito環境

public class LocalServiceImplMockTest {

@InjectMocks //此注解表示這個對象需要被注入mock對象

private LocalServiceImpl localService;

@Mock //此注解會自動創建1個mock對象并注入到@InjectMocks對象中

private RemoteServiceImpl remoteService;

//如果不使用上述注解,可以使用@Before方法來手動進行mock對象的創建和注入,但會幾行很多代碼

/*

private LocalServiceImpl localService;

private RemoteServiceImpl remoteService;

@Before

public void setUp() throws Exception {

localService = new LocalServiceImpl();

remoteService = Mockito.mock(RemoteServiceImpl.class); //創建Mock對象

Whitebox.setInternalState(localService, "remoteService", remoteService); //注入依賴對象

}

*/

@Test

public void testMock() {

Node target = new Node(1, "target"); //創建一個Node對象作為返回值

Mockito.when(remoteService.getRemoteNode(1)).thenReturn(target); //指定當remoteService.getRemoteNode(int)方法傳入參數為1時返回target對象

Node result = localService.getRemoteNode(1); //調用我們的業務方法,業務方法內部調用依賴對象方法

assertEquals(target, result); //可以斷言我們得到的返回值其實就是target對象

assertEquals(1, result.getNum()); //具體屬性和我們指定的返回值相同

assertEquals("target", result.getName()); //具體屬性和我們指定的返回值相同

Node result2 = localService.getRemoteNode(2); //未指定參數為2時對應的返回規則

assertNull(result2); //未指定時返回為null

}

}

spy外部依賴對象,并注入到我們的業務類中:

@RunWith(MockitoJUnitRunner.class)

public class LocalServiceImplSpyTest {

@InjectMocks

private LocalServiceImpl localService;

@Spy //注意這里使用的是@Spy注解

private RemoteServiceImpl remoteService;

//注意如果自己創建spy對象的話要這么寫:

/*

remoteService = new RemoteServiceImpl(); //先創建一個具體實例

remoteService = Mockito.spy(remoteService); //再調用Mockito.spy(T)方法創建spy對象

*/

@Test

public void testSpy() {

Node target = new Node(1, "target"); //創建一個Node對象作為返回值

Mockito.when(remoteService.getRemoteNode(1)).thenReturn(target); //指定當remoteService.getRemoteNode(int)方法傳入參數為1時返回target對象

Node result = localService.getRemoteNode(1); //調用我們的業務方法,業務方法內部調用依賴對象方法

assertEquals(target, result); //可以斷言我們得到的返回值其實就是target對象

assertEquals(1, result.getNum()); //具體屬性和我們指定的返回值相同

assertEquals("target", result.getName()); //具體屬性和我們指定的返回值相同

Node result2 = localService.getRemoteNode(2); //未指定參數為2時的調用規則,所以會直接調用真實對象,返回remote創建的節點

assertEquals(2, result2.getNum());

assertEquals("Node from remote service", result2.getName()); //remoteService創建Node對象時設置name屬性為"Node from remote service"

}

}

使用ArgumentMatchers的any系列方法指定多種返回值,有any()、anyInt()、anyString()、anyByte()、anyLong()等等,可以看下ArgumentMatchers類源碼中定義的所有方法:

@Test

public void testAny() {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(anyInt())).thenReturn(target); //靜態導入Mockito.when和ArgumentMatchers.anyInt后可以簡化代碼提升可讀性

Node result = localService.getRemoteNode(20); //上面指定了調用remoteService.getRemoteNode(int)時,不管傳入什么參數都會返回target對象

assertEquals(target, result); //可以斷言我們得到的返回值其實就是target對象

assertEquals(1, result.getNum()); //具體屬性和我們指定的返回值相同

assertEquals("target", result.getName()); //具體屬性和我們指定的返回值相同

}

指定mock對象多次調用的返回值:

/**

* 指定mock多次調用返回值

*/

@Test

public void testMultipleReturn() {

Node target1 = new Node(1, "target");

Node target2 = new Node(1, "target");

Node target3 = new Node(1, "target");

when(remoteService.getRemoteNode(anyInt())).thenReturn(target1).thenReturn(target2).thenReturn(target3);

//第一次調用返回target1、第二次返回target2、第三次返回target3

Node result1 = localService.getRemoteNode(1); //第1次調用

assertEquals(target1, result1);

Node result2 = localService.getRemoteNode(2); //第2次調用

assertEquals(target2, result2);

Node result3 = localService.getRemoteNode(3); //第3次調用

assertEquals(target3, result3);

}

指定mock對象拋出異常(注意如果方法中未聲明會拋出異常,只能指定拋出運行時異常,如果仍指定為拋出受檢查異常,運行時會報錯誤org.mockito.exceptions.base.MockitoException: Checked exception is invalid for this method!):

//RemoteServiceImpl方法:

@Override

public Node getRemoteNode(String name) throws MockException {

if (StringUtils.isEmpty(name)) {

throw new MockException("name不能為空", name);

}

return new Node(name);

}

//LocalServiceImpl方法

@Override

public Node getRemoteNode(String name) throws MockException {

try {

return remoteService.getRemoteNode(name);

} catch (IllegalArgumentException e) {

throw e;

}

}

/**

* 指定mock對象已聲明異常拋出的方法拋出受檢查異常

*/

@Test

public void testExceptionDeclare() {

try {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode("name")).thenReturn(target).thenThrow(new MockException(

"message", "exception")); //第一次調用正常返回,第二次則拋出一個Exception

Node result1 = localService.getRemoteNode("name");

assertEquals(target, result1); //第一次調用正常返回

Node result2 = localService.getRemoteNode("name"); //第二次調用不會正常返回,會拋出異常

assertEquals(target, result2);

} catch (MockException e) {

assertEquals("exception", e.getName()); //驗證是否返回指定異常內容

assertEquals("message", e.getMessage()); //驗證是否返回指定異常內容

}

}

/**

* 指定mock對象為聲明異常拋出的方法拋出運行時異常

*/

@Test

public void testRuntimeException() {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(1)).thenThrow(new RuntimeException("exception")); //指定調用時拋出一個運行時異常

try {

Node result = localService.getRemoteNode(1);

assertEquals(target, result);

} catch (RuntimeException e) {

assertEquals("exception", e.getMessage());

}

}

/**

* 指定mock對象未聲明異常拋出的方法拋出受檢查異常,以下方法執行會報錯

*/

@Test

public void testNotDefineCheckedException() {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(1)).thenThrow(new IOException("io exception"));

try {

Node result = localService.getRemoteNode(1);

assertEquals(target, result);

} catch (Exception e) {

assertEquals("io exception", e.getMessage());

}

}

mock void方法拋異常、什么都不做:

//RemoteServiceImpl方法:

@Override

public void doSometing() {

System.out.println("remote service do something!");

}

//LocalServiceImpl方法

@Override

public void remoteDoSomething() {

remoteService.doSometing();

}

//注意void方法沒有返回值,所以mock規則寫法順序不一樣

doNothing().when(remoteService).doSometing();

doThrow(new RuntimeException("exception")).when(remoteService).doSometing();

校驗mock對象的調用情況(除Mockito中的never()、times(int)方法外,還有atLeast(int)、atLeastOne()、atMost(int)等方法):

/**

* 校驗mock對象和方法的調用情況

*

*/

public void testVerify() {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(anyInt())).thenReturn(target);

verify(remoteService, never()).getRemoteNode(1); //mock方法未調用過

localService.getRemoteNode(1);

Mockito.verify(remoteService, times(1)).getRemoteNode(anyInt()); //目前mock方法調用過1次

localService.getRemoteNode(2);

verify(remoteService, times(2)).getRemoteNode(anyInt()); //目前mock方法調用過2次

verify(remoteService, times(1)).getRemoteNode(2); //目前mock方法參數為2只調用過1次

}

利用ArgumentCaptor捕獲方法參數進行mock方法參數校驗

/**

* 利用ArgumentCaptor捕獲方法參數進行mock方法參數校驗

*/

@Test

public void testCaptor() throws Exception {

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(anyString())).thenReturn(target);

localService.getRemoteNode("name1");

localService.getRemoteNode("name2");

verify(remoteService, atLeastOnce()).getRemoteNode(localCaptor.capture()); //設置captor

assertEquals("name2", localCaptor.getValue()); //獲取最后一次調用的參數

List list = localCaptor.getAllValues(); //按順序獲取所有傳入的參數

assertEquals("name1", list.get(0));

assertEquals("name2", list.get(1));

}

mock對象調用真實方法:

/**

* mock對象調用真實方法

*/

@Test

public void testCallRealMethod() {

when(remoteService.getRemoteNode(anyInt())).thenCallRealMethod(); //設置調用真實方法

Node result = localService.getRemoteNode(1);

assertEquals(1, result.getNum());

assertEquals("Node from remote service", result.getName());

}

重置mock對象:

//重置mock,清除所有的調用記錄和返回規則

Mockito.reset(remoteService);

校驗mock對象0調用和未被驗證的調用

/**

* 校驗mock對象0調用和未被驗證的調用

*/

@Test(expected = NoInteractionsWanted.class)

public void testInteraction() {

verifyZeroInteractions(remoteService); //目前還未被調用過,執行不報錯

Node target = new Node(1, "target");

when(remoteService.getRemoteNode(anyInt())).thenReturn(target);

localService.getRemoteNode(1);

localService.getRemoteNode(2);

verify(remoteService, times(2)).getRemoteNode(anyInt());

// 參數1和2的兩次調用都會被上面的anyInt()校驗到,所以沒有未被校驗的調用了

verifyNoMoreInteractions(remoteService);

reset(remoteService);

localService.getRemoteNode(1);

localService.getRemoteNode(2);

verify(remoteService, times(1)).getRemoteNode(1);

// 參數2的調用不會被上面的校驗到,所以執行會拋異常

verifyNoMoreInteractions(remoteService);

}

三、PowerMock的使用

PowerMock的使用與Mockito有一些不同,首先是測試類上的@RunWith注解需要修改為:

@RunWith(PowerMockRunner.class)

第二是需要使用到@PrepareForTest注解(PrepareFotTest注解會修改傳入參數類的字節碼,通過修改字節碼達到模擬final、static、私有方法、系統類等的功能),此注解可寫在類上也可寫在方法上:

@PrepareForTest(RemoteServiceImpl.class)

mock new關鍵字

//LocalServiceImpl

@Override

public Node getLocalNode(int num, String name) {

return new Node(num, name);

}

/**

* mock new關鍵字

*/

@Test

@PrepareForTest(LocalServiceImpl.class) //PrepareForTest修改local類的字節碼以覆蓋new的功能

public void testNew() throws Exception {

Node target = new Node(1, "target");

//當傳入任意int且name屬性為"name"時,new對象返回為target

//當參數條件使用了any系列方法時,剩余的參數都得使用相應的模糊匹配規則,如eq("name")代表參數等于"name"

//剩余還有isNull(), isNotNull(), isA()等方法

PowerMockito.whenNew(Node.class).withArguments(anyInt(), eq("name")).thenReturn(target);

Node result = localService.getLocalNode(2, "name");

assertEquals(target, result); //返回值為target

assertEquals(1, result.getNum());

assertEquals("target", result.getName());

//未指定name為"test"的返回值,默認返回null

Node result2 = localService.getLocalNode(1, "test");

assertNull(result2);

}

mock final方法

//RemoteServiceImpl

@Override

public final Node getFinalNode() {

return new Node(1, "final node");

}

/**

* mock final方法

*/

@Test

@PrepareForTest(RemoteServiceImpl.class) //final方法在RemoteServiceImpl類中

public void testFinal() {

Node target = new Node(2, "mock");

PowerMockito.when(remoteService.getFinalNode()).thenReturn(target); //指定返回值

Node result = remoteService.getFinalNode(); //直接調用final方法,返回mock后的值

assertEquals(target, result); //驗證返回值

assertEquals(2, result.getNum());

assertEquals("mock", result.getName());

}

mock static方法

//Node

public static Node getStaticNode() {

return new Node(1, "static node");

}

/**

* mock static方法

*/

@Test

@PrepareForTest(Node.class) //static方法定義在Node類中

public void testStatic() {

Node target = new Node(2, "mock");

PowerMockito.mockStatic(Node.class); //mock static方法前需要加這一句

PowerMockito.when(Node.getStaticNode()).thenReturn(target); //指定返回值

Node result = Node.getStaticNode(); //直接調用static方法,返回mock后的值

assertEquals(target, result); //驗證返回值

assertEquals(2, result.getNum());

assertEquals("mock", result.getName());

}

mock private方法

//RemoteServiceImpl

@Override

public Node getPrivateNode() {

return privateMethod();

}

//RemoteServiceImpl

private Node privateMethod() {

return new Node(1, "private node");

}

/**

* mock 私有方法

*/

@Test

@PrepareForTest(RemoteServiceImpl.class) //private方法定義在RemoteServiceImpl類中

public void testPrivate() throws Exception {

Node target = new Node(2, "mock");

//按照真實代碼調用privateMethod方法

PowerMockito.when(remoteService.getPrivateNode()).thenCallRealMethod();

//私有方法無法訪問,類似反射傳遞方法名和參數,此處無參數故未傳

PowerMockito.when(remoteService, "privateMethod").thenReturn(target);

Node result = remoteService.getPrivateNode();

assertEquals(target, result); //驗證返回值

assertEquals(2, result.getNum());

assertEquals("mock", result.getName());

}

mock 系統類方法

//RemoteServiceImpl

@Override

public Node getSystemPropertyNode() {

return new Node(System.getProperty("abc"));

}

/**

* mock 系統類方法

*/

@Test

@PrepareForTest(RemoteServiceImpl.class) //類似new關鍵字,系統類方法的調用在類RemoteServiceImpl中,所以這里填的是RemoteServiceImpl

public void testSystem() {

PowerMockito.mockStatic(System.class); //調用的是系統類的靜態方法,所以要加這一句

PowerMockito.when(System.getProperty("abc")).thenReturn("mock"); //設置System.getProperty("abc")返回"mock"

PowerMockito.when(remoteService.getSystemPropertyNode()).thenCallRealMethod(); //設置mock對象調用實際方法

Node result = remoteService.getSystemPropertyNode(); //按代碼會返回一個name屬性為"mock"的對象

assertEquals(0, result.getNum()); //int默認值為0

assertEquals("mock", result.getName()); //remoteService對象中調用System.getProperty("abc")返回的是上面設置的"mock"

}

項目代碼已上傳至GitHub:MockDemo

總結

以上是生活随笔為你收集整理的powermockito教程_Mockito与PowerMock的使用基础教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。