以下記錄 Mockito 在處理 static method,以及 final class/method 的方法。
準備
先準備一個要被 mock 的類別
import java.util.UUID;
public class DataUtils {
public static String getUuid() {
// return UUID.randomUUID().toString();
return "UUID";
}
public static String concat(String a, String b) {
return a+":"+b;
}
public final int finalMethod() {
return 1;
}
public String multiply(String a, int times) {
return a.repeat( times );
}
}
mock static method
- 沒有參數的 static method
Mockito.mockStatic(Class classToMock)
注意 MockedStatic 的 scope 問題,必須要放在 try-with-resources 裡面
@Test
// mock 沒有參數的 static method 的方法
public void mock_test1() {
assertEquals("UUID", DataUtils.getUuid());
// Mockito.mockStatic(Class<T> classToMock)
// 注意 MockedStatic 的 scope 問題,必須要放在 try-with-resources 裡面
// MockedStatic 必須要在 block 結束時,自動回收
try (MockedStatic<DataUtils> utils = mockStatic(DataUtils.class)) {
utils.when(DataUtils::getUuid).thenReturn("Custom UUID");
assertEquals("Custom UUID", DataUtils.getUuid());
}
assertEquals("UUID", DataUtils.getUuid());
}
- mock 有參數的 static method
@Test
// mock 有參數的 static method
public void mock_test2() {
assertEquals("A:B", DataUtils.concat("A", "B"));
// Mockito.mockStatic(Class<T> classToMock)
try (MockedStatic<DataUtils> utils = mockStatic(DataUtils.class)) {
utils.when(() -> DataUtils.concat("A", "B"))
.thenReturn( "A-B" );
assertEquals("A-B", DataUtils.concat("A", "B"));
}
assertEquals("A:B", DataUtils.concat("A", "B"));
}
- MockitoException
static mocking is already registered in the current thread 的 exception
@Test
public void mock_test3() {
// 將 utils 再一次 建立一個 mockStatic 物件時,會發生 exception
// org.mockito.exceptions.base.MockitoException:
// For mock.DataUtils, static mocking is already registered in the current thread
// To create a new mock, the existing static mock registration must be deregistered
assertThrows(MockitoException.class, () -> {
MockedStatic<DataUtils> utils = mockStatic(DataUtils.class);
utils = mockStatic(DataUtils.class);
});
}
- JUnit @Before @After
利用 JUnit 的 @Before @After,在每一次執行 @Test 的前後,處理 MockedStatic
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mockStatic;
public class DataUtilsMockitoTest2 {
private MockedStatic<DataUtils> mockStatic;
// @Before 會在每一次 @Test 之前被執行
@Before
public void before() {
// Registering a static mock for UserService before each test
mockStatic = mockStatic(DataUtils.class);
}
// @After 會在每一次 @Test 之後被執行
@After
public void after() {
// Closing the mockStatic after each test
mockStatic.close();
}
@Test
public void mock_test4_1() {
assertTrue(Mockito.mockingDetails(DataUtils.class).isMock());
mockStatic.when(() -> DataUtils.concat("A", "B"))
.thenReturn( "A-B" );
assertEquals("A-B", DataUtils.concat("A", "B"));
}
@Test
public void mock_test4_2() {
assertTrue(Mockito.mockingDetails(DataUtils.class).isMock());
mockStatic.when(() -> DataUtils.concat("A", "B"))
.thenReturn( "A*B" );
assertEquals("A*B", DataUtils.concat("A", "B"));
}
}
mock final class/method
先準備一個 final class
public final class DataUtilsFinal extends DataUtils {
public static String concat(String a, String b) {
return a+":"+b;
}
public String multiply(String a, int times) {
return a.repeat( times-1 );
}
}
- final method
@Test
public void mock_test1() {
// 直接用 mock 就可以使用 finalMethod
DataUtils dataUtils = new DataUtils();
DataUtils dataUtilsMock = mock(DataUtils.class);
when(dataUtilsMock.finalMethod()).thenReturn(0);
assertEquals(1, dataUtils.finalMethod());
assertEquals(0, dataUtilsMock.finalMethod());
}
- final class
@Test
public void mock_test2() {
// final class
DataUtilsFinal mock = mock(DataUtilsFinal.class);
when(mock.multiply("a", 2)).thenReturn("a");
assertEquals("a", mock.multiply("a", 2));
}
沒有留言:
張貼留言