Android:如何使用Robolectric运行PIT突变测试?

时间:2013-11-27 11:23:36

标签: java android eclipse robolectric pitest

如何使用Robolectric PIT来测试Android应用程序?

使用Robolectric,您可以在JVM中运行Android测试。使用PIT,您可以显示线路覆盖并进行突变测试。对我来说,可以使用Eclipse +插件,但没有要求。


这是我到目前为止所尝试的:

我有一个Android项目,我们称之为 MyProject

我现在想使用Robolectric PIT在JVM中测试MyProject。因此,我创建了另一个名为 MyTest 的项目,并设法成功运行Robolectric测试,就像robolectric quick start中所述。这就是my.app.tests.MyActivityTest的样子:

@RunWith(RobolectricTestRunner.class)
public class MyActivityTest {
    @Test
    public void myTest() throws Exception {
        String appName = new MainActivity().getResources().getString(R.string.app_name);
        Assert.assertEquals(appName, "MyProject");
    }
}

现在棘手的部分:我想在我的Robolectric测试中添加PIT的线覆盖和变异测试。首先尝试使用Pitclipse - 没有运气。 Pitclipse似乎还不支持Eclipse Project Depencies。

所以我的第二次尝试是使用命令行,如PIT quick start

中所述

首先,我确保我的测试在命令行中成功使用Junit:

java -cp <classpath> org.junit.runner.JUnitCore my.app.tests.MyActivityTest

<classpath>包含:junit4,robolectric,MyProject类文件,MyTest类文件,android.jar和其他必要的android库。

一旦这个JUnit测试成功,我在PIT调用中使用了相同的<classpath>,并在MyProject的根路径中执行该调用:

java -cp ../MyTest/bin:../MyTest/libs/*:bin/classes:~/android-sdk-linux/platforms/android-17/android.jar \
    org.pitest.mutationtest.MutationCoverageReport \
    --reportDir ../MyTest/pit-report \
    --targetClasses my.app.* \      # package in MyProject
    --targetTests my.app.tests.* \  # package in MyTest
    --sourceDirs src/

但是,这导致我在下面发布的例外情况。我想我需要使用PIT的--excludedClasses参数排除某些类,但是没有关于哪个类可能导致问题的提示。请注意,MyActivityTest没有超类,也没有显式构造函数。

java.lang.NullPointerException
ERROR Description [testClass=my.app.tests.MyActivityTest, name=myTest(my.app.tests.MyActivityTest)] -> java.lang.NullPointerException
    at org.pitest.boot.CodeCoverageStore.visitProbes(CodeCoverageStore.java:92)
    at my.app.tests.MyActivityTest.<init>(MyActivityTest.java:22)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:532)
    at org.junit.runners.BlockJUnit4ClassRunner.createTest(BlockJUnit4ClassRunner.java:195)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner.createTest(RobolectricTestRunner.java:647)
    at org.junit.runners.BlockJUnit4ClassRunner$1.runReflectiveCall(BlockJUnit4ClassRunner.java:244)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.BlockJUnit4ClassRunner.methodBlock(BlockJUnit4ClassRunner.java:241)
    at org.robolectric.RobolectricTestRunner$HelperTestRunner.methodBlock(RobolectricTestRunner.java:657)
    at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:227)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:175)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.pitest.junit.adapter.CustomRunnerExecutor.run(CustomRunnerExecutor.java:42)
    at org.pitest.junit.adapter.AdaptedJUnitTestUnit.execute(AdaptedJUnitTestUnit.java:86)
    at org.pitest.coverage.execute.CoverageDecorator.execute(CoverageDecorator.java:50)
    at org.pitest.containers.UnContainer.submit(UnContainer.java:46)
    at org.pitest.Pitest$3.run(Pitest.java:148)
    at java.lang.Thread.run(Thread.java:679)

1 个答案:

答案 0 :(得分:4)

正在发生的事情是正在加载pit的代码覆盖商店类的两个副本。这是一个跟踪每个测试的每个类的行覆盖范围的类。

测试中的类由加载时分配给它们的整数id标识 - 此id嵌入到通过调用代码覆盖存储类的字节码操作添加的探测调用中。

代码假定商店中每个类ID都有一个可用条目,因为每个id都在加载时向商店注册。由于接收探测调用的类的版本与最初注册类的类不同,因此该假设被破坏。

这是一个漫长的说法,0.31及以下的坑看起来与Roboelectric不兼容。

我需要仔细看看Roboelectric在幕后做了什么,看看是否可以在将来的版本中解决这个问题。

----更新---

0.32-SNAPSHOT版本似乎适用于Roboelectric(见评论)。