3

Android アプリケーションをテストするためにRobolectric PITを使用する方法は?

Robolectric を使用すると、JVM で Android テストを実行できます。PIT を使用すると、ライン カバレッジを表示し、突然変異テストを実行できます。私にとっては、Eclipse + Plugins を使用しても問題ありませんが、要件はありません。


これは私がこれまでに試したことです:

私は Android プロジェクトを持っています。これをMyProjectと呼びましょう。

Robolectric PITを使用して、JVM で MyProject をテストしたいと考えています。したがって、MyTestという別のプロジェクトを作成し、 robolectric クイック スタートで説明したように、Robolectric テストを正常に実行することができました。これは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");
    }
}

ここで注意が必要なのは、PIT の Line Coverage と Mutation Testing を Robolectric テストに追加したいということです。最初にPitclipseを使用しようとしましたが、うまくいきませんでした。Pitclipse はまだ Eclipse プロジェクトの依存関係をサポートしていないようです。

したがって、PIT クイック スタートで説明されているように、2 回目の試みはコマンド ラインを使用することです。

まず、コマンド ラインから Junit を使用して、テストが正常に実行されることを確認しました。

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

には<classpath>、junit4、robolectric、MyProject クラス ファイル、MyTest クラス ファイル、android.jar、およびその他の必要な Android ライブラリが含まれています。

この JUnit テストが成功し<classpath>たら、PIT 呼び出しで同じものを使用し、その呼び出しを 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)
4

1 に答える 1

4

起こっているように見えるのは、pit のコード カバレッジ ストア クラスの 2 つのコピーが読み込まれていることです。これは、各テストに対して各クラスのライン カバレッジを追跡するクラスです。

テスト対象のクラスは、ロード時に割り当てられる整数 ID によって識別されます。この ID は、コード カバレッジ ストア クラスを呼び出すバイトコード操作によって追加されるプローブ呼び出しに埋め込まれます。

コードは、ロード時に各 ID がストアに登録されるため、各クラス ID のストアに使用可能なエントリがあることを前提としています。プローブ呼び出しを受け取るクラスのバージョンは、クラスが最初に登録されたバージョンとは異なるため、この前提は崩れます。

これは、ピット 0.31 以下が Roboelectric と互換性がないように見えることを長い道のりで示しています。

Roboelectric が舞台裏で何をしているのかを正確に調べて、将来のリリースで修正できるかどうかを確認する必要があります。

- - アップデート - -

0.32-SNAPSHOT リリースは、Roboelectric で動作するようです (コメントを参照)。

于 2013-12-02T20:31:10.593 に答える