티스토리 뷰
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
댓글