0

Недавно я столкнулся с проблемой. Я пишу некоторые модульные тесты, чтобы использовать некоторые части моей библиотеки, ответственные за генерацию кода. Код вводит объект конфигурации, записывает код с использованием CodeModel, сбрасывает эти классы в String, а затем использует компилятор Java 6 api для компиляции их на лету в используемые классы.Тестирование сгенерированного кода Включая PowerMock

Ловушка, на которую я нахожусь, является одним из методов, которые я тестирую в сгенерированном коде, использует класс с окончательными методами (Android Bundle) и выдает исключения при использовании («java.lang.RuntimeException: Stub!»). Итак, чтобы обойти это, я использовал PowerMock, чтобы высмеять окончательные методы. В этом случае, однако, API-интерфейс компилятора выдает NPE. Я предполагаю, что это связано с тем, что PowerMock использует за кулисами, но я не уверен.

Вот исключение:

at org.androidtransfuse.gen.classloader.MemoryFileManager.<init>(MemoryFileManager.java:11) 
at org.androidtransfuse.gen.classloader.MemoryClassLoader.<init>(MemoryClassLoader.java:16) 
at org.androidtransfuse.gen.ParcelableGeneratorTest.setup(ParcelableGeneratorTest.java:67) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at org.junit.internal.runners.MethodRoadie.runBefores(MethodRoadie.java:129) 
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:93) 
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:296) 

MemoryFileManager.java:

class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> { 
    public final Map<String, Output> map = new HashMap<String, Output>(); 

    MemoryFileManager(JavaCompiler compiler) { 
     super(compiler.getStandardFileManager(null, null, null)); 
    } 

    @Override 
    public Output getJavaFileForOutput 
      (Location location, String name, JavaFileObject.Kind kind, FileObject source) { 
     Output mc = new Output(name, kind); 
     this.map.put(name, mc); 
     return mc; 
    } 
} 

MemoryClassLoader.java (который использует MemoryFileManager):

public class MemoryClassLoader extends ClassLoader { 
    private final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 
    private final MemoryFileManager manager = new MemoryFileManager(this.compiler); 

    public void add(String classname, String filecontent) { 
     add(Collections.singletonMap(classname, filecontent)); 
    } 

    public void add(Map<String, String> map) { 
     List<Source> list = new ArrayList<Source>(); 
     for (Map.Entry<String, String> entry : map.entrySet()) { 
      list.add(new Source(entry.getKey(), JavaFileObject.Kind.SOURCE, entry.getValue())); 
     } 
     this.compiler.getTask(null, this.manager, null, null, null, list).call(); 
    } 

    @Override 
    protected Class<?> findClass(String name) throws ClassNotFoundException { 
     synchronized (this.manager) { 
      Output mc = this.manager.map.remove(name); 
      if (mc != null) { 
       byte[] array = mc.toByteArray(); 
       return defineClass(name, array, 0, array.length); 
      } 
     } 
     return super.findClass(name); 
    } 
} 

И очень простой тест демонстрирует эту проблему :

@RunWith(PowerMockRunner.class) 
@PrepareForTest(Parcel.class) 
public class ExampleTest { 

    private static final String TEST_VALUE = "test value"; 

    String classToCompile = 
      "import android.os.Parcel;\n" + 
      "\n" + 
      "public class ClassToCompile\n" + 
      "{\n" + 
      "\n" + 
      " private Parcel parcel;\n" + 
      "}"; 

    @Test 
    public void test() throws ClassNotFoundException, IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { 
     MemoryClassLoader classLoader = new MemoryClassLoader(); 
     classLoader.add("ClassToCompile", classToCompile); 
     classLoader.loadClass("ClassToCompile"); 
    } 
} 

ответ

0

Johan on the Powermock Группа Google answered это для меня, но я думал, что добавлю результаты здесь также.

Что сработало для меня, меняется от подхода @RunWith (PowerMockRunner.class) к подходу Java Agent, описанного here.

Это требовал меня, чтобы удалить @RunWith аннотации и добавьте следующие строки в мой Maven POM:

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-surefire-plugin</artifactId> 
    <configuration> 
     <argLine> 
      -javaagent:${settings.localRepository}/org/powermock/powermock-module-javaagent/1.4.12/powermock-module-javaagent-1.4.12.jar 
     </argLine> 
    </configuration> 
</plugin> 

И при выполнении модульных тестов в среде IDE я должен был добавить

-javaagent: <jarpath>/powermock-module-javaagent-1.4.12.jar 

к .