網頁

2019/5/10

JUnit 4 Mockito 2搭配PowerMock來Mock靜態方法範例

JUnit 4測試時如果Mockito要對靜態方法(static method),final類別或方法,private方法等做mock,必須搭配PowerMock使用。

注意JUnit 4和JUnit 5設定上有不少差異,本範例僅適用於JUnit 4.4以上,Mockito 2版本。


在Maven的pom.xml<dependencies>中加入以下依賴。

<!-- JUnit 4 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
<!-- Mockito -->
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>2.27.0</version>
    <scope>test</scope>
</dependency>
<!-- PowerMock -->
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-module-junit4</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-mockito2</artifactId>
    <version>2.0.2</version>
    <scope>test</scope>
</dependency>

因為使用的JUnit 4版本為4.4以上,Mockito版本為2以上,所以PowerMock的設定如上,請參考Maven setup for the Mockito 2.x


以下分別為要被測式的方法DemoService.add()及被測式的方法中所依賴的靜態方法DemoUtil.add()

DemoService

public class DemoService {

    // 要被測試的方法
    public int add(int x, int y) {
        return DemoUtil.add(x, y);
    }
}

DemoUtil是一個Helper工具類別,因此類別和方法都宣告為final,PowerMock仍可對其mock。

DemoUtil

public final class DemoUtil {
    
    private DemoUtil() {
    }
    
    // 被DemoService.add()依賴的靜態方法
    public static final int add(int x, int y) {
        return x + y;
    }

}

下面則是負責對DemoService進行測試的測試類別DemoServiceTest

在測試類別上掛上@RunWith(PowerMockRunner.class)@PrepareForTest({DemoUtil.class})@PrepareForTest的值為要被Mock的靜態方法的類別,也就是DemoUtil.class

然後在測試方法testAddGiven1And2()中要呼叫PowerMockito.mockStatic(DemoUtil.class);來告訴PowerMock傳入的DemoUtil.class的所有靜態方法都要被mock。

DemoServiceTest

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.abc.board.util.DemoUtil;

@RunWith(PowerMockRunner.class) // 必須使用PowerMockRunner
@PrepareForTest({DemoUtil.class}) // 告訴PowerMock準備要被Mock的靜態類別,可以設定多個。
public class DemoServiceTest {
    
    private DemoService demoSerivce = new DemoService();
    
    // 負責測試DemoService.add()
    @Test
    public void testAddGiven1And2() {
        int x = 1; int y = 2;
        int expected = x + y;

        PowerMockito.mockStatic(DemoUtil.class); // 告訴PowerMock DemoUtil中的靜態方法都要被Mock
        Mockito.when(DemoUtil.add(x, y)).thenReturn(expected);

        int actual = demoSerivce.add(x, y);
        
        Assert.assertEquals(expected, actual);
        
    }

}

因為DemoUtil.add()static final 方法,所以必須透過PowerMock才能對其進行Mock的動作。

PowerMock是透過其類別載入器(ClassLoader)及直接操作位元組碼(bytecode)來達到以上目的。


參考:

沒有留言:

張貼留言