Android Robolectric 3.0과 Powermock을 같이 쓰기 SW

Android Test 환경은 Robolectric, Powermock 등 여러 라이브러리로 구성합니다. (Android에서 Test 환경 참조)

이 경우 여러 라이브러리를 동시에 사용한다면 개별 test 환경들이 각자 @RunWith Annotation을 사용하는 Runner를 제공하기 때문에 문제가 될 수 있습니다. Android에서 Robolectric 3.0 RC 버전과 Powermock을 같이 사용하는 방법을 정리하였습니다.

이 경우 기본적으로 Robolectric의 Runner를 사용하고, Powermock은 runtime code로 다응합니다.
build.gradle
depepdencies {
testCompile 'junit:junit:4.12'
testCompile 'org.robolectric:robolectric:3.0-rc3'
testCompile 'org.robolectric:shadows-support-v4:3.0-rc3'

// PowerMock brings in the mockito dependency
testCompile "org.powermock:powermock-module-junit4:1.6.2"
testCompile "org.powermock:powermock-module-junit4-rule:1.6.2"
testCompile "org.powermock:powermock-classloading-xstream:1.6.2"
testCompile "org.powermock:powermock-api-mockito:1.6.2"
}
와 같이 설정 해 주고, 코드에서는

@RunWith(RobolectricGradleTestRunner.class)
@PrepareForTest({EnclosingClass.class})
@PowerMockIgnore({"org.robolectric.*", "android.*"})
public class Test {
@Rule
public PowerMockRule rule = new PowerMockRule();

@Test
public void test1() throws Exception {
PowerMockito.whenNew(StaticClass.class).WithAnyArguments().thenReturn(true);
}
}
와 같이 @Rule 을 설정 해 주고 PowerMock을 사용합니다.

다만, 이 경우 현재 버전 기준으로 SDK 21에서는 제대로 실행되지 않습니다. 관련 이슈는PowerMock fails with API 21, works in 18 and 19 에 다음과 같이 설명되어 있습니다.

The problem here is that in API 21, the KXmlParser class uses an internal version of System.arraycopy , which is available in the android.jar, but not in the desktop Java. That is why that special method cannot be found.

To make that work, you have to load the standard version of kxml on the classpath, instead of the Android one. This is not easy but doable, however it could break other things which are expected from the Android implementation.

Robolectric에서 구현을 바꾸면 되지만 일단 이 문제는 위의 link에 있는 것처럼 다음과 같이 회피가 가능합니다.
build gradle에서

testCompile 'com.thoughtworks.xstream:xstream:1.4.2'
// testCompile "org.powermock:powermock-classloading-xstream:1.6.2" // remove this dep
위의 line을 추가하고, 아래 라인을 제거합니다. 이러면 powermock의 DeepCloner에서 에러가 나는데, 다음의 코드를 추가합니다.

package org.powermock.classloading;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.Xpp3Driver;

import org.powermock.classloading.spi.DeepClonerSPI;

public class DeepCloner implements DeepClonerSPI {
private final XStream xStream;

public DeepCloner(ClassLoader classLoader) {
xStream = new XStream(null, null, new Xpp3Driver());
xStream.omitField(ClassloaderExecutor.class, "classloader");
xStream.setClassLoader(classLoader);
}

public T clone(T objectToClone) {
final String serialized = xStream.toXML(objectToClone);
return (T) xStream.fromXML(serialized);
}
}

Test 환경을 위해서 라이브러리를 학습해야 하는 부분이 많네요.