티스토리 뷰

Overview

Private Method를 테스트 하다보니 Reflection을 사용하여 작성을 하여 번거로움이 있었습니다.
라이브러리의 힘을 빌려 PowerMock 으로 Private Method 를 Mocking하여 유닛테스트를 작성해봅니다.

Gradle Dependencies

아래의 의존성을 추가해줍니다.
powermock-module-junit4
powermock-api-mockito2

testImplementation(
"org.powermock:powermock-module-junit4:2.0.9",
"org.powermock:powermock-api-mockito2:2.0.9"
)

Service Layer

아래의 public 메소드가 있습니다. isNewOrder 는 private 메소드이고, mocking 하여 public 메소드를 Unit 테스트를 해봅니다.

public class CoffeeOrderService {

    private static final String[] ORDER_ID_LIST = {"A10131", "A10132", "A10133"};

    public String getOrderId(String orderId) {
        if(isNewOrder(orderId)){
            orderId = RandomStringUtils.random(5);
        }
        return orderId;
    }

    private boolean isNewOrder(String orderId){
        return Stream.of(ORDER_ID_LIST)
                .anyMatch(orderItem -> orderItem.equals(orderId));
    }

}

Unit Test

Use PowerMock

@RunWith(PowerMockRunner.class)
@PrepareForTest(CoffeeOrderService.class)
public class CoffeeOrderServiceTest {

    private CoffeeOrderService spiedCoffeeOrderService;

    @Before
    public void setUp() {
        spiedCoffeeOrderService = PowerMockito.spy(new CoffeeOrderService());
    }

    @Test
    public void should_getNewOrderId_When_NewOrder() throws Exception {
        String orderId = "A10131";

        when(spiedCoffeeOrderService, "isNewOrder", anyString()).thenReturn(true);
        String actualOrderId = spiedCoffeeOrderService.getOrderId(orderId);

        verifyPrivate(spiedCoffeeOrderService).invoke("isNewOrder", anyString());
        assertNotEquals(orderId, actualOrderId);
    }

    @Test
    public void should_getExistingOrderId_When_OldOrder() throws Exception {
        String orderId = "A10131";

        when(spiedCoffeeOrderService, "isNewOrder", anyString()).thenReturn(false);
        String actualOrderId = spiedCoffeeOrderService.getOrderId(orderId);

        verifyPrivate(spiedCoffeeOrderService).invoke("isNewOrder", anyString());
        assertEquals(orderId, actualOrderId);
    }
 }

PowerMockito.when 메소드로 private method를 mocking 해줍니다.
PowerMockito.verifyPrivate 메소드는 private method가 호출되었는지 검증합니다.

Syntax

when(mock or spy instance, "privateMethodName").thenReturn(//return value);

verifyPrivate(mockedInstance).invoke("privateMethodName");

@PrepareForTest

Failure

처음에 @PrepareForTest 를 붙이지 않았다가 아래와 같은 에러를 받았다.

Misplaced or misused argument matcher detected here:

메소드를 타겟으로 해당 어노테이션을 붙이니 테스트가 깨지고 아래와같은 에러를 받았다.

@PrepareForTest(CoffeeOrderService.class)
    public void should_getNewOrderId_When_NewOrder() throws Exception {
    ...


FAILURE: Build failed with an exception.
filter.includeTestsMatching

Success

@RunWith(PowerMockRunner.class)
@PrepareForTest(CoffeeOrderService.class)
public class CoffeeOrderServiceTest {
...

클래스를 타겟으로 하니 테스트가 정상 작동합니다.

Use Reflection

번외로 Reflection을 이용하여 private method를 직접 테스트 해봅니다.

    @Test
    public void test_isNewOrder_method_byReflection() throws Exception {
        CoffeeOrderService coffeeOrderService = new CoffeeOrderService();

        Method m = coffeeOrderService.getClass().getDeclaredMethod("isNewOrder", String.class);
        m.setAccessible(true);

        // orderIdList : {"A10131", "A10132", "A10133"}
        boolean isNewOrder = (boolean) m.invoke(coffeeOrderService, "Z99999");    
        boolean isNewOrder2 = (boolean) m.invoke(coffeeOrderService, "A10131");

        assertEquals(false, isNewOrder);
        assertEquals(true, isNewOrder2);
    }

 

Reference

Baeldung - powermock-private-method
Software Testing Help - Mocking Private, Static And Void Methods Using Mockito

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함
Total
Today
Yesterday