1. 程式人生 > >在Springboot中編寫Mock單元測試

在Springboot中編寫Mock單元測試

1.概要

軟體測試是一個應用軟體質量的保證。java開發者開發介面往往忽視介面單元測試。作為java開發如果會Mock單元測試,那麼你的bug量將會大大降低。spring提供test測試模組,所以現在小胖哥帶你來玩下springboot下的Mock單元測試,我們將對controller,service 的單元測試進行實戰操作。

2.依賴引入

按照上面引入依賴而且scope為test。該依賴提供了一下類庫

  • JUnit 4: 目前最強大的java應用單元測試框架

  • Spring Test & Spring Boot Test: Spring Boot 整合測試支援.

  • AssertJ: 一個java斷言庫,提供測試斷言支援.

  • Hamcrest: 物件匹配斷言和約束元件.

  • Mockito: 知名 Java mock 模擬框架.

  • JSONassert: JSON斷言庫.

  • JsonPath: JSON XPath 操作類庫.

以上都是在單元測試中經常接觸的類庫。有時間你最好研究一下。

3.配置測試環境

一個Spring Boot 應用程式是一個Spring ApplicationContext ,一般測試不會超出這個範圍。

測試框架提供一個@SpringBootTest註解來提供SpringBoot單元測試環境支援。你使用的JUnit版本如果是JUnit 4不要忘記在測試類上新增@RunWith(SpringRunner.class),JUnit 5就不需要了。預設情況下,@SpringBootTest不會啟動伺服器。您可以使用其webEnvironment 屬性進一步優化測試的執行方式,webEnvironment 相關講解:

  • MOCK(預設):載入Web ApplicationContext並提供模擬Web環境。該選擇下不會啟動嵌入式伺服器。如果類路徑上沒有Web環境,將建立常規非Web的ApplicationContext。你可以配合@AutoConfigureMockMvc或@AutoConfigureWebTestClient模擬的Web應用程式。
  • RANDOM_PORT:載入aWebServerApplicationContext並提供真實的Web環境,啟用的是隨機web容器埠。
  • DEFINED_PORT:載入WebServerApplicationContext並提供真實的Web環境 和RANDOM_PORT不同的是啟用你啟用的SpringBoot應用埠,通常都宣告在application.yml配置檔案中。
  • NONE:通過SpringApplication載入一個ApplicationContext。但不提供 任何 Web環境(無論是Mock或其他)。

注意事項:如果你的測試帶有@Transactional註解時,預設情況下每個測試方法執行完就會回滾事務。但是當你的webEnvironment 設定為RANDOM_PORT或者 DEFINED_PORT,也就是隱式地提供了一個真實的servlet web環境時,是不會回滾的。這一點特別重要,請確保不會在生產釋出測試中寫入髒資料。

4.編寫測試類測試你的api

言歸正傳,首先我們編寫了一個BookService 作為Service 層

其實現類如下,為了簡單明瞭沒有測試持久層,如果持久層需要測試注意增刪改需要Spring事務註解@Transactional支援以達到測試後回滾的目的。

controller層如下

我們在Spring Boot maven專案的單元測試包test下對應的類路徑 編寫自己的測試類

前兩個註解不用說,第三個註解可能你們很陌生。這個是用來開啟Mock Mvc測試的自動化配置的。

然後我們編寫一個測試方法來測試BookApi#getBook(String title)介面。

簡單講解一下 MockMvc 執行一個模擬的get請求然後期望結果是expect Json字串並且將相應物件列印了出來(下圖1標識)。一旦請求不通過將丟擲java.lang.AssertionError錯誤, 會把期望值(Expected)跟實際值打印出來(下圖2標識)。如果跟預期相同只會出現下圖1。

5.測試打樁

有個很常見的情形,在開發中有可能你呼叫的其他服務沒有開發完,比如你有個簡訊傳送介面還在辦理簡訊介面手續,但是你還需要簡訊介面來進行測試。你可以通過@MockBean 構建一個抽象介面的實現。拿上面的BookService來說,假如其實現類邏輯還沒有確定,我們可以通過規定其入參以及對應的返回值來模擬這個bean的邏輯,或者根據某個情形下進行某個路由操作的選擇(如果入參是A則結果為B,如果為C則D)。這種模擬也被成為測試打樁。 這裡我們會用到Mockito

測試場景描述如下:

  • 指定打樁物件的返回值
  • 判斷某個打樁物件的某個方法被呼叫及呼叫的次數
  • 指定打樁物件丟擲某個特定異常

一般有以下幾種組合:

  • do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…)
  • given/will:包括given(…).willReturn(…)/given(…).willAnswer(…)
  • when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)

其他都好理解,著重介紹一下Answer , Answer 正是為了解決如果入參是A則結果為B,如果為C則D這種路由操作的。接下來我們實操一下 ,跟最開始基本一樣,只是更換成@MockBean

然後利用Mockito編寫打樁方法,模擬上面BookServiceImpl 實現類。不過模擬的bean每次測試完都會自動重置。而且不能用於模擬在應用程式上下文重新整理期間執行的bean的行為。

然後把這個方法注入controller 測試方法就可以測試了。

6.其他

內建的assertj也是常用的斷言,api非常友好,這裡也簡單演示一下

7.總結

本文中實現了一些簡單的Spring Boot啟用整合測試。 對測試環境的搭建,測試程式碼的編寫進行了實戰操作,基本能滿足日常開發測試需要,相信你能從本文學到不少東西。相關的講解程式碼可以從https://gitee.com/felord/mock