Mockito가 지원하는 기능은 간단한 기능의 유닛테스트에는 충분하지만 코드 구조가 복잡할 경우 테스트하기에 힘든 부분이 많다. 혹은 반대로, 테스트를 위해서 좋은 코드 구조를 포기해야만 하는 경우도 있다. PowerMock은 그런 문제들을 피해 유닛테스트를 할 수 있게 도와준다. 이 글은 PowerMock의 Wiki를 보고 나름대로 정리한 것이다.

이 글의 모든 예제 코드는 JUnit v4.12, PowerMock v1.6.6, Mockito v1.10.+ 을 기준으로 작성되었다. 추가로 PowerMock v1.6.6 기준으로 Mockito v2나 EasyMock도 지원한다. 공식 위키에 훨씬 더 자세한 내용이 있다.

 

Setup

다음과 같이 build.gradle에 패키지를 추가하고 Gradle sync를 실행하자. 순서대로 JUnit v4.12, PowerMock v1.6.6, 그리고 PowerMock v1.6.6과 호환되는 Mockito 버전(작성기준 v1.10.19)을 설치한다.

또, PowerMock을 JUnit test에 사용하기 위해 @RunWith(PowerMockRunner.class) Annotation을 원하는 Test class에 추가해주자.

캡슐화 우회 (Bypass Encapsulation)

캡슐화 우회를 위한 메소드들은 모두 org.powermock.reflect.Whitebox 패키지에 정의되어 있다. 패키지의 이름에서도 알 수 있듯이 모든 기능은 리플랙션(reflection)으로 만들어졌다. 사실 이 패키지를 사용하지 않고도 직접 리플랙션 코드로 private 필드나 메소드에 접근할 수 있다. 하지만 역시 이런 세세한 기능을 직접 만드려면 수고가 많이 들기 때문에 Powermock을 사용하는 것을 추천한다.

Private field access

Getter나 setter가 없어서 private 필드에 접근이 불가능 할 때 setInternalState()/getInternalState()메소드를 이용하면 접근이 가능하다.

이름 혹은 타입으로 특정 private 필드에 접근한다. 필드 타입으로 접근하면 코드를 짤 때는 손쉽지만, 따로 주석을 달아놓지 않는 이상 나중에 테스트 코드를 수정할 때 어느 필드에 접근하는 건지 바로 알기 어렵다는 단점이 있다. 또, 같은 타입의 필드가 여러개 있을 경우 타입으로 접근하는 것이 불가능하다. 코드가 조금 더 길어지더라도 필드 이름으로 접근하는 것이 길게 봤을 때 좋다.

Private method invocation

invokeMethod()로 private 메소드를 호출할 수 있다.

private 필드를 이름 혹은 타입으로 찾는 것처럼, invokeMethod()이름 또는 메소드 파라미터 타입으로 메소드를 찾는다. 같은 파라미터 타입을 가진 메소드가 또 있으면 호출이 불가능하므로 이름까지 꼭 적어주는 편이 좋다.

Super class’ private field access / method invocation

심지어 오버라이드(override)되어서 직접 접근할 수 없는 부모 클래스의 필드나 메소드에도 접근이 가능하다. 위의 예제들과 똑같이 setInternalState()/getInternalState()/invokeMethod()메소드를 사용한다.

기존과 똑같이 사용하지만 접근하려는 특정 클래스 타입을 추가 파라미터로 넣어주면 된다. 일반적으로 오버라이드된 필드나 메소드를 접근할 일은 거의 없어서 그냥 이런 기능이 있다 정도만 알아두면 될 듯하다.

Private constructor invocation

자주 사용할 일은 없겠지만 private 생성자를 직접 호출하는 것도 가능하다.

관련글