以下記錄 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));
    } 
沒有留言:
張貼留言