Android: как запустить тестирование мутации PIT с помощью Robolectric?

Как использовать Robolectric и PIT для тестирования приложения Android?

С помощью Robolectric вы можете запускать тесты Android в JVM. С помощью PIT вы можете показать покрытие линии и провести тестирование на мутации. Для меня нормально использовать плагины Eclipse +, но не обязательно.


Это то, что я пробовал до сих пор:

У меня есть проект Android, назовем его MyProject.

Теперь я хочу протестировать MyProject в JVM, используя Robolectric и НДФЛ. Поэтому я создал еще один проект под названием MyTest, и мне удалось успешно запустить робоэлектрические тесты, как описано в быстрое начало работы с роботом. Вот как выглядит 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 в свои робоэлектрические тесты. Сначала попробовал использовать Pitclipse - не повезло. Pitclipse, похоже, еще не поддерживает зависимости проекта Eclipse.

Итак, моя вторая попытка - использовать командную строку, как описано в Быстрый запуск PIT:

Во-первых, я убедился, что мои тесты прошли успешно, используя 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)

person sulai    schedule 27.11.2013    source источник
comment
Я бы начал использовать плагин maven - это часть основной кодовой базы PIT. Плагин eclipse является сторонним и менее зрелым. Я не знаком с разработкой Android или Roboelectric, но из быстрого поиска в Google кажется, что он должен работать с PIT, пока на диск где-то записывается обычный байт-код jvm. Если у вас есть успех (или неудача), отправьте сообщение в группу пользователей ямы google.   -  person henry    schedule 27.11.2013
comment
@henry Во второй попытке я попытался использовать PIT из командной строки. Обычные тесты JUnit (без использования робототехники) хорошо работают с PIT. Однако MyActivityTest, использующий robolectric, выдает сообщение об исключении, указанное выше. Вы хоть представляете, в чем может быть проблема?   -  person sulai    schedule 29.11.2013
comment
У меня нет опыта работы с PIT. Как происходит мутация? Robolectric имеет собственный загрузчик классов и выполняет манипуляции с байт-кодом во время полета. Вот почему нет четкого понимания, как его использовать с такими библиотеками, как PowerMock.   -  person Eugen Martynov    schedule 29.11.2013


Ответы (1)


Похоже, что происходит загрузка двух копий класса хранилища покрытия кода пита. Это класс, который отслеживает покрытие строк для каждого класса по каждому тесту.

Тестируемые классы идентифицируются по целочисленному идентификатору, который присваивается им при загрузке - этот идентификатор встроен в пробные вызовы, добавленные манипуляциями с байт-кодом, которые вызывают класс хранилища покрытия кода.

Код предполагает, что в магазине будет доступная запись для каждого идентификатора класса, поскольку каждый идентификатор регистрируется в магазине при загрузке. Это предположение неверно, поскольку версия класса, получающего пробные вызовы, отличается от той, для которой классы были первоначально зарегистрированы.

Это длинный способ сказать, что яма 0,31 и ниже не выглядит совместимой с Roboelectric.

Мне нужно посмотреть, что именно Roboelectric делает за кулисами, чтобы увидеть, можно ли это исправить в будущем выпуске.

---- Обновлять ---

Версия 0.32-SNAPSHOT, похоже, работает с Roboelectric (см. Комментарии).

person henry    schedule 02.12.2013
comment
Я знаю, что сделать PIT совместимым с Robolectric может быть непросто. Однако и PIT, и Robolectric извлекут из этого большую пользу. Было бы приятно увидеть, как оба работают вместе :) - person sulai; 03.12.2013
comment
Теперь это отслеживается как code.google.com/p/pitestrunner/issues. / detail? id = 84. Похоже, что это может быть очень простое исправление, которое может быть сделано на стороне RoboElectric. Я бы предпочел поискать более общее исправление в коде ямы - возможно, каким-то образом переместите функциональность хранилища покрытия в пакет java.lang, чтобы он был защищен от всех проблем с загрузчиком классов, не связанных с делегированием. - person henry; 03.12.2013
comment
@sulai Блокировщик с магазином покрытия был удален в последней версии 0.32-SNAPSHOT. При использовании github.com/robolectric/RobolectricSample он работает без ошибок. Однако оценка мутации выглядит подозрительно низкой, поэтому могут возникнуть дополнительные проблемы. - person henry; 04.12.2013
comment
Снимок уже доступен? Я попробовал maven-repository.com/artifact/org.pitest. Я не в том месте? - person sulai; 10.12.2013
comment
Снимки не доходят до maven central - они доступны в репозиториях sonatype oss.sonatype.org/content/repositories/snapshots/org/pitest - person henry; 10.12.2013
comment
PIT сейчас проходит через мой довольно большой андроид-проект со 171 java-файлом - ошибок нет, и отчет мне очень интересен! Большое вам спасибо за ваши усилия в этом деле! Если я могу быть полезен, дайте мне знать. Может быть, я смогу внести свой вклад, написав в каком-нибудь месте короткое руководство по робототехнике PIT +? - person sulai; 11.12.2013
comment
Рад слышать, что это работает - пример проекта Android, на котором я его пробовал, в основном приводил к тайм-аутам. Похоже, это произошло не из-за RoboElectric, а из-за чего-то другого. Если вы хотите описать свой опыт, это было бы здорово. - person henry; 11.12.2013