Как получить покрытие в SonarQube из Maven Multiproject с помощью PowerMock и Jacoco Offline Instrumentation

У меня мультипроектная сборка Maven. Я использую Powermock для имитации классов для написания модульных тестов. Итак, чтобы получить покрытие jacoco, я использую автономные инструменты Jacoco и устанавливаю sonar.dynamicAnalysis = reuseReports, чтобы получить покрытие сонара. Когда я пытаюсь это сделать, я получаю ошибки от Jacoco и Sonar:

[INFO] Analysing C:\Program Files (x86)\Jenkins\workspace\Test\target\jacoco.exec
[WARNING] Exception during analysis of file C:\Program Files (x86)\Jenkins\workspace\Test\target\classes\cache\TestClass.class
java.io.IOException: Error while analyzing 
C:\Program Files (x86)\Jenkins\workspace\Test\target\classes\cache\TestClass.class
    at org.jacoco.core.analysis.Analyzer.analyzerError(Analyzer.java:155)
    at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:130)
    at org.jacoco.core.analysis.Analyzer.analyzeClass(Analyzer.java:147)
    at org.sonar.plugins.jacoco.JacocoReportReader.analyzeClassFile(JacocoReportReader.java:139)
    at org.sonar.plugins.jacoco.JacocoReportReader.analyzeFiles(JacocoReportReader.java:114)
    at org.sonar.plugins.jacoco.AbstractAnalyzer.readExecutionData(AbstractAnalyzer.java:133)
    at org.sonar.plugins.jacoco.AbstractAnalyzer.analyse(AbstractAnalyzer.java:102)
    at org.sonar.plugins.jacoco.JaCoCoSensor.execute(JaCoCoSensor.java:87)
    at org.sonar.scanner.sensor.SensorWrapper.analyse(SensorWrapper.java:53)
    at org.sonar.scanner.phases.SensorsExecutor.executeSensor(SensorsExecutor.java:88)
    at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:82)
    at org.sonar.scanner.phases.SensorsExecutor.execute(SensorsExecutor.java:68)
    at org.sonar.scanner.phases.AbstractPhaseExecutor.execute(AbstractPhaseExecutor.java:88)
    at org.sonar.scanner.scan.ModuleScanContainer.doAfterStart(ModuleScanContainer.java:180)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:144)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:129)
    at org.sonar.scanner.scan.ProjectScanContainer.scan(ProjectScanContainer.java:286)
    at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:281)
    at org.sonar.scanner.scan.ProjectScanContainer.scanRecursively(ProjectScanContainer.java:279)
    at org.sonar.scanner.scan.ProjectScanContainer.doAfterStart(ProjectScanContainer.java:259)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:144)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:129)
    at org.sonar.scanner.task.ScanTask.execute(ScanTask.java:48)
    at org.sonar.scanner.task.TaskContainer.doAfterStart(TaskContainer.java:84)
    at org.sonar.core.platform.ComponentContainer.startComponents(ComponentContainer.java:144)
    at org.sonar.core.platform.ComponentContainer.execute(ComponentContainer.java:129)
    at org.sonar.scanner.bootstrap.GlobalContainer.executeTask(GlobalContainer.java:121)
    at org.sonar.batch.bootstrapper.Batch.doExecuteTask(Batch.java:118)
    at org.sonar.batch.bootstrapper.Batch.execute(Batch.java:72)
    at org.sonarsource.scanner.api.internal.batch.BatchIsolatedLauncher.execute(BatchIsolatedLauncher.java:46)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.sonarsource.scanner.api.internal.IsolatedLauncherProxy.invoke(IsolatedLauncherProxy.java:60)
    at com.sun.proxy.$Proxy19.execute(Unknown Source)
    at org.sonarsource.scanner.api.EmbeddedScanner.doExecute(EmbeddedScanner.java:171)
    at org.sonarsource.scanner.api.EmbeddedScanner.execute(EmbeddedScanner.java:128)
    at org.sonarsource.scanner.maven.bootstrap.ScannerBootstrapper.execute(ScannerBootstrapper.java:63)
    at org.sonarsource.scanner.maven.SonarQubeMojo.execute(SonarQubeMojo.java:108)
    at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
    at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
    at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
    at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
    at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:347)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:154)
    at org.apache.maven.cli.MavenCli.execute(MavenCli.java:582)
    at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
    at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
    at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
    at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: java.lang.IllegalStateException:cache\TestClass is already instrumented.
    at org.jacoco.core.internal.instr.InstrSupport.assertNotInstrumented(InstrSupport.java:176)

Я не уверен, почему jacoco снова пытается инструментировать класс, чтобы получить покрытие сонара. Я застрял с этой проблемой какое-то время. Любая помощь была бы замечательной.

Пожалуйста, редактировать ваш вопрос, чтобы включить версию SonarJava, которая находится в Администрировании -> Marketplace в версиях 6.7+ и в Администрировании -> Система -> Центр обновлений в 6.6 и ниже.

G. Ann - SonarSource Team 11.04.2018 14:27

Пример использования PowerMock с JaCoCo Offline Instrumentation и Maven в нашем репозитории: github.com/powermock/powermock-examples-maven/tree/master/…. Затем вы можете импортировать покрытие в SonarQube любым подходящим способом.

VaL 11.04.2018 21:58

@VaL Я могу получить файл данных, созданный Жакоко. Проблема в том, что в Jenkins, когда я пытаюсь запустить сонар как часть CI, он выдает ошибку. Я не уверен, почему сонар снова пытается инструментировать классы.

Farhee Aslam 12.04.2018 05:19

@ G.Ann-SonarSourceTeam Версия SonarJava: 4.14.0.11784

Farhee Aslam 12.04.2018 08:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
648
2

Ответы 2

Согласно http://www.jacoco.org/jacoco/trunk/doc/instrument-mojo.html:

Performs offline instrumentation. Note that after execution of test you must restore original classes with help of "restore-instrumented-classes" goal.

Сообщение об исключении already instrumented вводит в заблуждение, но именно это сообщение выдается при попытке проанализировать инструментированные классы вместо исходных.

<execution><id>default-instrument</id><goals> <goal> инструмент </goal> </goals> </ ex‌ ecution> <execution> <‌ id> default-restore-i‌ nstrumented-classes <‌ / id> <goals> <goal> res‌ tore-Instrumented-cl‌ asses </goal> </goals> ‌ </execution>. Я также добавил "классы с инструментами восстановления". Я вижу проблему, когда сонар пытается проанализировать файл данных.

Farhee Aslam 13.04.2018 06:32

Анализ \ target \ jacoco.exec [ВНИМАНИЕ] Исключение при анализе файла \ cache \ TestClass.class. И ошибка вызвана тем, что он снова пытается инструментировать TestClass. Я вижу, что он анализирует jacoco.exec, а затем анализирует целевой класс и пытается его инструментировать.

Farhee Aslam 13.04.2018 06:40

@FarheeAslam, как разработчик JaCoCo и SonarQube, могу заверить вас, что во время анализа никогда не выполняется контрольно-измерительная аппаратура. Еще раз - сообщение об ошибке и трассировка стека четко указывают на то, что вы пытаетесь анализировать инструментированный класс, тогда как необходимо проанализировать оригинал и все. Безумная догадка - может, вы просто забыли сделать clean после добавления restore-instrumented-classes?

Godin 13.04.2018 13:37

В Jenkins я выполняю следующие инструкции: 1) mvn clean install -DskipTests 2) mvn clean test 3) mvn -Psonar org.sonarsource.scanner.maven: sonar-maven-plugin: 3.4.0.905: s‌ onar -Dsonar.projectKey = TestProject. Подскажите, пожалуйста, какой из шагов здесь не так? @Godin

Farhee Aslam 16.04.2018 10:19

проблема для меня - когда я выполняю третью команду «mvn -Psonar org.sonarsource.scanner.maven: sonar-maven-plugin: 3.4.0.905: s‌ onar -Dsonar.projectKey = TestProject»

Farhee Aslam 16.04.2018 10:22

@FarheeAslam согласно уже упомянутой документации (jacoco.org/jacoco/trunk/doc/…) restore-instrumented-classes по умолчанию привязывается к prepare-package, который идет после test - см. maven.apache.org/guides/introduction/… Поэтому не выполняется, когда вы выполняете mvn clean test, и почти уверен, что журналы показывают, что он не выполняется. Это будет выполнено, например, в случае mvn clean verify.

Godin 16.04.2018 19:42

Я не уверен, что происходит в вашем случае, но мне удалось создать покрытие PowerMock с помощью Jacoco, используя powermock-module-javaagent.

Только не забудьте поставить powermock agent после jacoco agent:

<artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <useSystemClassLoader>true</useSystemClassLoader>
                <argLine>${jacocoArgLine} -javaagent:${settings.localRepository}/org/powermock/powermock-module-javaagent/${powermock.version}/powermock-module-javaagent-${powermock.version}.jar -noverify</argLine>
...

Если вы хотите увидеть пример, взгляните на этот проект: https://github.com/jfcorugedo/sonar-scanner

Здесь вы можете видеть, что сонар учитывает статические методы и операторы new, издевательские PowerMock:

Если вы хотите имитировать заявления new, убедитесь, что вы используете PowerMockRule вместо PowerMockRunner.

Взгляните на этот тест

Другие вопросы по теме