使用Mockito模擬靜態方法
- Mockito
- java
1.概述
通常,在編寫單元測試時,我們會遇到需要模擬靜態方法的情況。在Mockito的3.4.0版本之前,不可能直接模擬靜態方法–僅在PowerMockito的幫助下。
在本教程中,我們將研究如何使用最新版本的Mockito模擬靜態方法。要了解有關使用Mockito進行測試的更多信息,請查看我們全面的Mockito系列。
2.一個簡單的靜態實用程序類
在整個教程中,我們測試的重點將是一個簡單的靜態實用程序類:
public class StaticUtils {
private StaticUtils() {}
public static List<Integer> range(int start, int end) {
return IntStream.range(start, end)
.boxed()
.collect(Collectors.toList());
}
public static String name() {
return "1ju.org";
}
}
為了演示的目的,我們有一個方法帶有一些參數,而另一種方法僅返回String
。
3.依存關係
讓我們開始吧,向我們的pom.xml
mockito-inline
依賴項:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
值得注意的是,在某些時候,根據文檔,此功能很可能已集成到更熟悉的mockito-core
依賴中。
4.快速測試靜態方法
一般來說,有人可能會說,在編寫乾淨的面向對象的代碼時,我們不需要模擬靜態類。這通常可能暗示我們的應用程序中存在設計問題或代碼異味。
首先,因為依賴於靜態方法的類具有緊密的耦合,其次,它幾乎總是導致難以測試的代碼。理想情況下,類不應負責獲取其依賴項,並且如果可能的話,應該從外部注入它們。
因此,始終值得研究是否可以重構代碼以使其更具可測試性。當然,這並非總是可能的,有時我們不得不模擬靜態方法。
5.模擬一個無參數的靜態方法
讓我們繼續前進,看看如何從StaticUtils
類中name
@Test
void givenStaticMethodWithNoArgs_whenMocked_thenReturnsMockSuccessfully() {
assertThat(StaticUtils.name()).isEqualTo("Baeldung");
try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
utilities.when(StaticUtils::name).thenReturn("Eugen");
assertThat(StaticUtils.name()).isEqualTo("Eugen");
}
assertThat(StaticUtils.name()).isEqualTo("1ju.org");
}
如前所述,自Mockito 3.4.0起,我們可以使用Mockito.mockStatic( Class<T> classToMock )
方法來模擬對靜態方法調用的調用。此方法MockedStatic
對象,這是一個有範圍的模擬對象。
因此,在上面的單元測試中, utilities
變量表示具有線程局部顯式作用域的模擬。重要的是要注意,作用域模擬必須由激活該模擬的實體關閉。這就是為什麼我們在try-with-resources構造中定義模擬程序的原因,以便當我們完成作用域塊時自動關閉模擬程序。
這是一個特別不錯的功能,因為它可以確保我們的靜態模擬仍然是臨時的。眾所周知,如果在測試運行過程中使用靜態方法調用,由於運行測試的並發性和順序性,這很可能對測試結果造成不利影響。
最重要的是,另一個好處是我們的測試仍然可以超級快速地運行,因為Mockito不需要為每個測試都替換類加載器。
在我們的示例中,我們通過在作用域塊之前和之後檢查靜態方法name
返回實值來再次重申這一點。
6.用參數模擬靜態方法
現在,讓我們看看需要模擬帶有參數的方法時的另一個常見用例:
@Test
void givenStaticMethodWithArgs_whenMocked_thenReturnsMockSuccessfully() {
assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);
try (MockedStatic<StaticUtils> utilities = Mockito.mockStatic(StaticUtils.class)) {
utilities.when(() -> StaticUtils.range(2, 6))
.thenReturn(Arrays.asList(10, 11, 12));
assertThat(StaticUtils.range(2, 6)).containsExactly(10, 11, 12);
}
assertThat(StaticUtils.range(2, 6)).containsExactly(2, 3, 4, 5);
}
如我們所見,除了這次,我們使用了與lambda表達式相同的方法,除了這次,我們在when
子句中使用了lambda表達式。非常簡單!
7.結論
在這篇快速的文章中,我們已經看到了一些示例,這些示例說明瞭如何使用Mockito模擬靜態方法。總之,Mockito通過一個較小的lambda為狹窄的模擬靜態對象提供了一種範圍更廣的解決方案。