一、當需要mock靜態方法的時候,必須加注解@PrepareForTest和@RunWith。注解@PrepareForTest里寫的類是靜態方法所在的類。
import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.eq; @RunWith(PowerMockRunner.class) @PrepareForTest(String.class) public class MockPrepareForTest { @Test public void testStaticMathod () { TestString testString = new TestString(); PowerMockito.mockStatic(String.class); PowerMockito.when(String.valueOf(eq(100l))).thenReturn("TEST"); String result = testString.getTestString(100l); assertEquals("TEST", result); } class TestString { public String getTestString(long number) { return String.valueOf(number); } } }
以上模擬靜態方法的方式僅適用於JDK8 以下的版本,如果你想在JDK8+的版本模擬靜態方法,可以用以下的方式。
二、使用最新版本的 Mockito 模擬靜態方,我們測試的重點將是一個簡單的靜態實用程序類:
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 "Baeldung"; } }
- 添加依賴
讓我們開始將mockito-inline依賴項添加到我們的pom.xml:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>3.8.0</version> <scope>test</scope> </dependency>
- 模擬無參靜態方法
@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("Baeldung"); }
如前所述,從 Mockito 3.4.0 開始,我們可以使用Mockito.mockStatic( Class<T> classToMock )方法來模擬對靜態方法調用的調用。此方法為我們的類型返回一個MockedStatic對象,它是一個作用域模擬對象。
因此,在我們上面的單元測試中,utilities變量表示具有線程局部顯式作用域的模擬。需要注意的是,作用域模擬必須由激活模擬的實體關閉。這就是為什么我們在try-with-resources構造中定義我們的模擬,以便當我們完成我們的作用域塊時模擬會自動關閉。
這是一個特別好的功能,因為它確保我們的靜態模擬保持臨時。正如我們所知,如果我們在測試運行期間使用靜態方法調用,由於運行測試的並發和順序特性,這可能會對我們的測試結果產生不利影響。
最重要的是,另一個很好的副作用是我們的測試仍然會運行得非常快,因為 Mockito 不需要為每個測試替換類加載器。
- 用參數模擬靜態方法
現在讓我們看看另一個常見的用例,當我們需要模擬一個有參數的方法時:
@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); }
在這里,我們遵循相同的方法,但這次我們在我們的when子句中使用lambda 表達式,我們在其中指定方法以及我們想要模擬的任何參數。