在 JUnit 5 方法參數中註入 @Mock 和 @Captor
1. 概述
在本教程中,我們將了解如何在單元測試方法參數中註入@Mock
和@Captor
註解。
我們可以在單元測試中使用@Mock
來建立模擬物件。另一方面,我們可以使用@Captor
來捕獲和儲存傳遞給模擬方法的參數以供以後斷言。 JUnit 5 的引入使得將參數注入測試方法變得非常容易,為這項新功能騰出了空間。
2. 設定範例
為了讓此功能發揮作用,我們需要使用 JUnit 5。可以在Maven Central Repository中找到該程式庫的最新版本。讓我們將依賴項加入pom.xml
:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>
Mockito是一個測試框架,它允許我們建立動態模擬物件。 Mockito Core 提供了該框架的基本功能,提供了用於創建模擬物件並與之互動的富有表現力的 API。讓我們使用它的最新版本:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
最後,我們需要使用 Mockito JUnit Jupiter 擴展,它負責將 Mockito 與 JUnit 5 整合。讓我們將此依賴項添加到pom.xml
中:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
3.透過方法參數注入@Mock
首先,讓我們將 Mockito 擴充附加到我們的單元測試類別中:
@ExtendWith(MockitoExtension.class)
class MethodParameterInjectionUnitTest {
// ...
}
註冊 Mockito 擴充功能允許 Mockito 框架與 JUnit 5 測試框架整合。因此,我們現在可以提供模擬物件作為測試參數:
@Test
void whenMockInjectedViaArgumentParameters_thenSetupCorrectly(@Mock Function<String, String> mockFunction) {
when(mockFunction.apply("bael")).thenReturn("dung");
assertEquals("dung", mockFunction.apply("bael"));
}
在此範例中,當我們傳遞“bael”
作為輸入時,我們的模擬函數會傳回String
“dung”
。該斷言表明模擬的行為符合我們的預期。
此外,建構函式也是一種方法,因此也可以將@Mock
作為測試類別建構子的參數注入:
@ExtendWith(MockitoExtension.class)
class ConstructorInjectionUnitTest {
Function<String, String> function;
public ConstructorInjectionUnitTest(@Mock Function<String, String> functionr) {
this.function = function;
}
@Test
void whenInjectedViaArgumentParameters_thenSetupCorrectly() {
when(function.apply("bael")).thenReturn("dung");
assertEquals("dung", function.apply("bael"));
}
}
總的來說,模擬注入並不局限於基本的單元測試。例如,我們也可以將模擬注入其他類型的可測試方法中,例如重複測試或參數化測試:
@ParameterizedTest
@ValueSource(strings = {"", "bael", "dung"})
void whenInjectedInParameterizedTest_thenSetupCorrectly(String input, @Mock Function<String, String> mockFunction) {
when(mockFunction.apply(input)).thenReturn("baeldung");
assertEquals("baeldung", mockFunction.apply(input));
}
最後,我們要注意,當我們將模擬注入參數化測試時,方法參數的順序很重要。注入的mockFunction
模擬必須位於input
測試參數之後,參數解析器才能正確完成其工作。
4.透過方法參數注入@Captor
ArgumentCaptor
允許檢查我們在測試中無法透過其他方式存取的物件的值。我們現在可以透過方法參數以非常相似的方式註入@Captor
:
@Test
void whenArgumentCaptorInjectedViaArgumentParameters_thenSetupCorrectly(@Mock Function<String, String> mockFunction, @Captor ArgumentCaptor<String> captor) {
mockFunction.apply("baeldung");
verify(mockFunction).apply(captor.capture());
assertEquals("baeldung", captor.getValue());
}
在此範例中,我們將模擬函數應用於String
“baeldung”
。然後,我們使用ArgumentCaptor
來提取傳遞給函數呼叫的值。最後我們驗證這個值是否正確。
我們關於模擬注射的所有評論也適用於綁架者。特別地,讓我們來看看這次在@RepeatedTest
中註入的範例:
@RepeatedTest(2)
void whenInjectedInRepeatedTest_thenSetupCorrectly(@Mock Function<String, String> mockFunction, @Captor ArgumentCaptor<String> captor) {
mockFunction.apply("baeldung");
verify(mockFunction).apply(captor.capture());
assertEquals("baeldung", captor.getValue());
}
5. 為什麼要使用方法參數注入?
我們現在來看看這個新功能的優點。首先,讓我們回顧一下之前我們是如何聲明模擬的:
Mock<Function> mock = mock(Mock.class)
在這種情況下,編譯器會發出警告,因為Mockito.mock()
無法正確建立Function
的泛型類型。由於方法參數注入,我們能夠保留泛型類型簽名,並且編譯器不再抱怨。
使用方法注入的另一個巨大優點是發現依賴關係。之前,我們需要檢查測試程式碼以了解與其他類別的交互作用。透過方法參數注入,方法簽章顯示了我們的被測系統如何與其他元件互動。此外,測試程式碼更短並且更專注於其目標。
六,結論
在本文中,我們了解如何透過方法參數注入@Mock
和@Captor
。 JUnit 5 中對建構函式和方法依賴注入的支援啟用了此功能。總之,建議使用這個新功能。乍一看,它可能只是一個錦上添花的東西,但它可以提高我們的程式碼品質和可讀性。
與往常一樣,範例的程式碼可以在 GitHub 上取得。