日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

詳解Java 中的UnitTest 和 PowerMock

瀏覽:134日期:2022-08-31 16:39:44

學習一門計算機語言,我覺得除了學習它的語法外,最重要的就是要學習怎么在這個語言環(huán)境下進行單元測試,因為單元測試能幫你提早發(fā)現(xiàn)錯誤;同時給你的程序加一道防護網(wǎng),防止你的修改破壞了原有的功能;單元測試還能指引你寫出更好的代碼,畢竟不能被測試的代碼一定不是好代碼;除此之外,它還能增加你的自信,能勇敢的說出「我的程序沒有bug」。

每個語言都有其常用的單元測試框架,本文主要介紹在 Java 中,我們如何使用 PowerMock,來解決我們在寫單元測試時遇到的問題,從 Mock 這個詞可以看出,這類問題主要是解依賴問題。

在寫單元測試時,為了讓測試工作更簡單、減少外部的不確定性,我們一般都會把被測類和其他依賴類進行隔離,不然你的類依賴得越多,你需要做的準備工作就越復雜,尤其是當它依賴網(wǎng)絡或外部數(shù)據(jù)庫時,會給測試帶來極大的不確定性,而我們的單測一定要滿足快速、可重復執(zhí)行的要求,所以隔離或解依賴是必不可少的步驟。

而 Java 中的 PowerMock 庫是一個非常強大的解依賴庫,下面談到的 3 個特性,可以幫你解決絕大多數(shù)問題:

1 通過 PowerMock 注入依賴對象

2 利用 PowerMock 來 mock static 函數(shù)

3 輸出參數(shù)(output parameter)怎么 mock

通過 PowerMock 注入依賴對象

假設你有兩個類,MyService 和 MyDao,MyService 依賴于 MyDao,且它們的定義如下

// MyDao.java@Mapperpublic interface MyDao { /** * 根據(jù)用戶 id 查看他最近一次操作的時間 */ Date getLastOperationTime(long userId);}// MyService.java@Servicepublic class MyService {@Autowiredprivate MyDao myDao; public boolean operate(long userId, String operation) { Date lastTime = myDao.getLastOperationTime(userId); // ... }}

這個服務提供一個 operate 接口,用戶在調用該接口時,會被限制一個操作頻次,所以系統(tǒng)會記錄每個用戶上次操作的時間,通過 MyDao.getLastOperationTime(long userId) 接口獲取,現(xiàn)在我們要對 MyService 類的 operate 做單元測試,該怎么做?

你可能會想到使用 SpringBoot,它能自動幫我們初始化 myDao 對象,但這樣做卻存在一些問題:

1 SpringBoot 的啟動速度很慢,這會延長單元測試的時間

2 因為時間是一個不斷變化的量,也許這一次你構造的時間滿足測試條件,但下一次運行測試時,可能就不滿足了。

由于以上原因,我們一般在做單元測試時,不啟動 SpringBoot 上下文,而是采用 PowerMock 幫我們注入依賴,對于上面的 case,我們的測試用例可以這樣寫:

// MyServiceTest.java@RunWith(PowerMockRunner.class)@PrepareForTest({MyService.class, MyDao.class})public class MyServiceTest { @Test public void testOperate() throws IllegalAccessException { // 構造一個和當前調用時間永遠只差 4 秒的返回值 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.SECOND, -4); Date retTime = calendar.getTime();// spy 是對象的“部分 mock” MyService myService = PowerMockito.spy(new MyService()); MyDao md = PowerMockito.mock(MyDao.class); PowerMockito.when(md.getLastOperationTime(Mockito.any(long.class))).thenReturn(retTime); // 替換 myDao 成員 MemberModifier.field(MyService.class, 'myDao').set(myService, md); // 假設最小操作的間隔是 5 秒,否則返回 false Assert.assertFalse(myService.operate(1, 'test operation')); }}

從上面代碼中,我們首先構造了一個返回時間 retTime,模擬操作間隔的時間為 4 秒,保證了每次運行測試時該條件不會變化;然后我們用 spy 構造一個待測試的 MyService 對象,spy 和 mock 的區(qū)別是,spy 只會部分模擬對象,即這里只修改掉 myService.myDao 成員,其他的保持不變。

然后我們定義了被 mock 的對象 MyDao md 的調用行為,當 md.getLastOperationTime 函數(shù)被調用時,返回我們構造的時間 retTime,此時測試環(huán)境就設置完畢了,這樣做之后,你就可以很容易的測試 operate 函數(shù)了。

利用 PowerMock 來 mock static 函數(shù)

上文所說的使用 PowerMock 進行依賴注入,可以覆蓋測試中絕大多數(shù)的解依賴場景,而另一種常見的依賴是 static 函數(shù),例如我們自己寫的一些 CommonUtil 工具類中的函數(shù)。

還是使用上面的例子,假設我們要計算當前時間和用戶上一次操作時間之間的間隔,并使用 public static long getTimeInterval(Date lastTime) 實現(xiàn)該功能,如下:

// CommonUtil.javaclass CommonUtil { public static long getTimeInterval(Date lastTime) { long duration = Duration.between(lastTime.toInstant(),new Date().toInstant()).getSeconds(); return duration; }}

我們的 operator 函數(shù)修改如下

// MyService.java// ... public boolean operate(long userId, String operation) { Date lastTime = myDao.getLastOperationTime(userId); long duration = CommonUtil.getTimeInterval(lastTime); if (duration >= 5) { System.out.println('user: ' + userId + ' ' + operation); return true; } else { return false; } }// ...

這里先從 myDao 獲取上次操作的時間,再調用 CommonUtil.getTimeInterval 計算操作間隔,如果小于 5 秒,就返回 false,否則執(zhí)行操作,并返回 true。那么我的問題是,如何解掉這里 static 函數(shù)的依賴呢?我們直接看測試代碼吧

// MyServiceTest.java@PrepareForTest({MyService.class, MyDao.class, CommonUtil.class})public class MyServiceTest {// ... @Test public void testOperateWithStatic() throws IllegalAccessException { // ... PowerMockito.spy(CommonUtil.class); PowerMockito.doReturn(5L).when(CommonUtil.class); CommonUtil.getTimeInterval(Mockito.anyObject()); // ... }}

首先在注解 @PrepareForTest 中增加 CommonUtil.class,依然使用 spy 對類 CommonUtil 進行 mock,如果不這么做,這個類中所有靜態(tài)函數(shù)的行為都會發(fā)生變化,這會給你的測試帶來麻煩。spy 下面的兩行代碼你應該放在一起解讀,意為當調用 CommonUtil.getTimeInterval 時,返回 5;這種寫法比較奇怪,但卻是 PowerMock 要求的。至此,你已經(jīng)掌握了 mock static 函數(shù)的技巧。

輸出參數(shù)(output parameter)怎么 mock

有些函數(shù)會通過修改參數(shù)所引用的對象作為輸出,例如下面的這個場景,假設我們的 operation 是一個長時間執(zhí)行的任務,我們需要不斷輪訓該任務的狀態(tài),更新到內存,并對外提供查詢接口,如下代碼:到內存,并對外提供查詢接口,如下代碼:

// MyTask.java// ... public boolean run() throws InterruptedException { while (true) { updateStatus(operation); if (operation.getStatus().equals('success')) {return true; } else {Thread.sleep(1000); } } } public void updateStatus(Operation operation) { String status = myDao.getStatus(operation.getOperationId()); operation.setStatus(status); }// ...

上面的代碼中,run() 是一個輪詢任務,它會不斷更新 operation 的狀態(tài),并在狀態(tài)達到 'success' 時停止,可以看到,updateStatus 就是我們所說的函數(shù),雖然它沒有返回值,但它會修改參數(shù)所引用的對象,所以這種參數(shù)也被稱作輸出參數(shù)。

現(xiàn)在我們要測試 run() 函數(shù)的行為,看它是否會在 'success' 狀態(tài)下退出,那么我們就需要 mock updateStatus 函數(shù),該怎么做?下面是它的測試代碼:

@Test public void testUpdateStatus() throws InterruptedException { // 初始化被測對象 MyTask myTask = PowerMockito.spy(new MyTask()); myTask.setOperation(new MyTask.Operation()); // 使用 doAnswer 來 mock updateStatus 函數(shù)的行為 PowerMockito.doAnswer(new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable {Object[] args = invocation.getArguments();MyTask.Operation operation = (MyTask.Operation)args[0];operation.setStatus('success');return null; } }).when(myTask).updateStatus(Mockito.any(MyTask.Operation.class)); Assert.assertEquals(true, myTask.run()); }

上面的代碼中,我們使用 doAnswer 來 mock updateStatus 的行為,相當于使用 answer 函數(shù)來替換原來的 updateStatus 函數(shù),在這里,我們將 operation 的狀態(tài)設置為了 'success',以期待 myTask.run() 函數(shù)返回 true。于是,我們又學會了如何 mock 具有輸出參數(shù)的函數(shù)了。

以上就是詳解Java 中的UnitTest 和 PowerMock的詳細內容,更多關于Java UnitTest 和 PowerMock的資料請關注好吧啦網(wǎng)其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久理论电影| 欧美精品中文| 麻豆高清免费国产一区| 美国三级日本三级久久99| 最新国产拍偷乱拍精品| av一区二区高清| 久久久精品午夜少妇| 亚洲国产福利| 亚洲天堂1区| 亚洲二区在线| 久久www成人_看片免费不卡| 巨乳诱惑日韩免费av| 免费观看在线色综合| 日韩在线黄色| 国产精品亚洲人成在99www | 欧洲激情综合| 夜夜精品视频| 日精品一区二区三区| 91精品国产一区二区在线观看| 日韩高清一级| 鲁鲁在线中文| 日本欧美久久久久免费播放网| 午夜亚洲福利在线老司机| 亚洲少妇在线| 亚洲另类av| 日韩精品一级| 欧美黄页在线免费观看| 日韩综合在线| 免费观看不卡av| 中文字幕成人| 国产精品对白久久久久粗| 久久精品99久久久| 精品99在线| 亚洲女同中文字幕| 亚洲日产国产精品| 国产精品久一| 在线观看精品| 国产精品毛片| 国产精品久久久久久久免费软件| 在线人成日本视频| 制服诱惑一区二区| 久久国内精品自在自线400部| 精品一区二区三区免费看| 久久中文字幕av一区二区不卡| 在线综合亚洲| 美女久久99| 欧美91福利在线观看| 午夜性色一区二区三区免费视频| 蜜桃久久久久| 在线天堂中文资源最新版| 国产精品va| 久久精品国产大片免费观看| 亚洲精品欧洲| 国产不卡人人| 蜜臀精品久久久久久蜜臀| 国产精品tv| 在线亚洲国产精品网站| 久久99影视| 好看不卡的中文字幕| 国产精品日韩精品在线播放| 欧美13videosex性极品| 99国产成+人+综合+亚洲欧美| 日韩va欧美va亚洲va久久| 水蜜桃久久夜色精品一区| 免费一区二区视频| 老牛影视精品| 日韩av黄色在线| 午夜日韩在线| 久久久久黄色| 亚洲丝袜美腿一区| 日本少妇一区| 国产三级精品三级在线观看国产| 欧美丝袜一区| 麻豆精品少妇| 亚洲三级网站| 亚洲黄色在线| 成人一二三区| 日韩av二区在线播放| 国产精品久久久久久久久久白浆| 欧美特黄一区| 精品国产99| 亚洲一级淫片| 91精品国产调教在线观看| 国产美女撒尿一区二区| 亚洲成人免费| 国产成人精品一区二区三区免费| 免播放器亚洲一区| 欧美在线观看视频一区| 麻豆精品一区二区综合av| 日韩久久一区| 日韩午夜av在线| 丰满少妇一区| 日韩成人午夜精品| 午夜在线一区| 欧美国产91| 成人羞羞在线观看网站| 久久99影视| 国产日韩高清一区二区三区在线| 中文亚洲免费| 精品中文一区| 天堂√8在线中文| 精品一区二区三区中文字幕| 欧美午夜三级| 亚洲视频二区| 国产亚洲一级| 伊人精品在线| 欧美成人久久| 在线视频观看日韩| 久久黄色影院| 九九综合九九| 九九九精品视频| 日韩av电影一区| 亚洲欧洲av| 日韩在线a电影| 香蕉成人久久| 亚洲深夜影院| 野花国产精品入口| 最新日韩欧美| 人人爽香蕉精品| 亚洲色图网站| 视频一区日韩精品| 亚洲一区二区网站| 欧美日韩国产亚洲一区| 激情婷婷亚洲| 91久久亚洲| 亚洲在线久久| 91免费精品国偷自产在线在线| 亚洲区第一页| 欧美亚洲色图校园春色| 日韩和欧美一区二区| 日韩精品三区四区| 97精品久久| 国产精品对白久久久久粗| 麻豆国产一区| 日韩欧美精品| 亚洲午夜黄色| 亚洲成人三区| 水野朝阳av一区二区三区| 亚洲精品影院在线观看| 日日摸夜夜添夜夜添国产精品| 少妇精品久久久一区二区| 欧洲av一区二区| 精品国产亚洲日本| 精品国产一区二| 伊伊综合在线| 久久精品1区| 亚洲欧美久久久| 秋霞影院一区二区三区| 欧美一区二区三区高清视频| 欧美一区久久| 日韩高清在线不卡| 亚洲青青久久| 免费观看不卡av| 免费观看在线综合色| 国产亚洲字幕| 精品网站999| 久久精品中文| 久久亚洲图片| 国产午夜一区| 中文字幕在线视频网站| 日韩视频久久| 91伊人久久| 精品免费av在线| 视频一区二区欧美| 欧美国产亚洲精品| 成人看片网站| 中文不卡在线| 国产精品亚洲产品| 久久国产99| 精品国产18久久久久久二百| 日本免费久久| 鲁大师成人一区二区三区| 日韩av不卡一区二区| 欧美日韩黄网站| 日韩大片在线观看| 青草久久视频| 国产精品xvideos88| 久久影视一区| 日韩av一区二区在线影视| 精品视频一区二区三区在线观看| 久久精品主播| 青草国产精品久久久久久| 欧美激情aⅴ一区二区三区 | 欧美日韩 国产精品| 高清不卡亚洲| 亚洲另类视频| 中文在线资源| 一区二区日韩免费看| 91欧美在线| 亚洲精品国产精品粉嫩| 日韩精品永久网址| 日韩超碰人人爽人人做人人添| 亚洲性色av| 日本国产一区| 日韩在线看片| 国产欧美日韩精品高清二区综合区 | 一区二区精品| 国产精品99视频| 五月激激激综合网色播| sm捆绑调教国产免费网站在线观看|