Android studio test coverage

Android+Kotlin Code coverage with Jacoco, Sonar and Gradle plugin 6.x

Sep 21, 2020 · 7 min read

At Wandera, we have been measuring our code coverage for quite a while, but we relied on a 3rd party plugin that solved the Jacoco plugin configuration for us because we didn’t want to deal with Groovy language for speed and simplicity.

We were dealing with two issues — we were using an outdated Gradle plugin and we were missing the instrumentation test coverage in our reports.

When we upgraded the Gradle plugi n to the newest version ( 6.6.1 as of writing this blogpost), it wasn’t all sunshine and rainbows with the then-used 3rd party plugin as it had not been maintained for a good year.

I learned the plugins are quite simple to implement, so to encourage you not to use 3rd party plugins when it is not necessary, I’d like to present you with a thorough guideline.

We are going to go through how to setup Jacoco plugin, how to setup the client part of Sonar, how to be able to choose one or both the jvm and instrumentation tests code coverage and what to watch out for when using version 6.x of the Gradle plugin.

Jacoco plugin

Firstly, you will want to add Jacoco plugin to your project.
Add classpath “ org.jacoco:org.jacoco.core:0.8.5 ” to your project.


Version 0.8.5 contains a small bug so if you want to avoid any issues, use a different version instead
https://github.com/jacoco/jacoco/issues/968

Coverage configuration

Now we will want to compute coverage of JVM unit tests and Android instrumentation tests.

You can configure Jacoco in your module’s build.gradle file, but it is much cleaner to have larger configurations separated in new gradle files for easier maintenance. A separate file may also be reused across modules or projects.

Contents of the jacoco.gradle file (located where the module’s build.gradle file is) explained below:

Gradle tasks

We created a task for each variant of our app. So if you have a debug, dev and release variant, you should see testDebugUnitTestCoverage, testDevUnitTestCoverage and testReleaseUnitTestCoverage Gradle tasks in your right-side Gradle tab in Android Studio. You may name the jobs whatever you like.

Then we need to declare that our testXxxUnitTestCoverage task depends on running the tests so that we have some data to compute the coverage from. We cannot start with computation until the necessary output files are generated.

To enable Android Instrumentation tests coverage, your module’s build.gradle file should look like this:

Important: the Android Instrumentation test coverage works only if you set your application variant’s property testCoverageEnabled true

When the test coverage is not enabled, the testXxxUnitTestCoverage tasks for such variants won’t work unless you exclude androidTestCoverageData from dependencies (for instance by not depending on the task and by not expecting the report to be available for execution data).

On the other hand, you only need to keep track of one of your variants which usually is the debug one.

Report files

Moving on, we specify the types of reports we want to have generated.

HTML format is the most human-friendly. XML and CSV reports are used for other reporting tools, for instance Sonar or a CI plugin.

Sources

We need to tell Jacoco where to find our Java and Kotlin classes

You can see the build directory can be referenced variably.

If you don’t include the java classes, any tests written in java won’t be taken into account. Same for Kotlin.

Читайте также:  Пароль для сброса настроек андроид автомагнитолы

Then we want to exclude generated classes that we cannot cover with tests and would make the coverage unnecessarily low. These are usually classes generated by 3rd parties during compilation, such as Dagger/Hilt, Butterknife, Kotlin etc. You may exclude anything you consider unnecessary to appear in your reports.

I enriched my list by looking in the following sources.

Gradle plugin 6.x update

In one of the newest Gradle plugin versions, some properties were made read-only. That’s one of the reasons most of the abandoned 3rd party plugins have stopped working. Setter methods must be used instead.

So instead of a direct assignment, setters must be used.

You may want to add certain directories for a specific variant type.

You can do so in

Tests data

At last we need to specify where to find the execution data.

An .exec file is created for the JVM unit tests and a similar file of .ec type is created for Android instrumentation files.

We define both of these paths using the Jacoco’s executionData property.

If you only want to track coverage of your unit tests, don’t add the androidTestsData path. The same goes for the instrumentation tests.

For future reference, some Android plugin versions change the build dir hierarchy, so in case it is not working in the future, make sure the files are generated at the path you provided. If not, change the path to the directory the files now appear in.

You can find the description of each Jacoco property by following the below link.

Apply the plugin

Now that we have the plugin configuration done, we need to make sure it is applied.

In your app’s build.gradle file, add the following line apply from: “ jacoco.gradle” so it looks like the following:

Now when you run

you should see your reports appear in the Jacoco directory.

Watch out for the Gradle plugin version!

This whole story started with updating the Android Gradle plugin to version 4 as the Android Studio likes to warn us about new updates.

When you update the Android Gradle plugin version, it usually comes with updating the Gradle wrapper version to be compatible as per the documentation on the official site https://developer.android.com/studio/releases/gradle-plugin

And when you are updating, you usually select the latest version possible. So we did update the gradle-wrapper.properties file:

After that, our automated builds started failing on not having the Jacoco reports available!

After the whole day and night of searching for all possible issues with Jacoco I finally bumped into the Gradle issues Github site saying the Gradle plugin version 6.4 makes the Android connected tests run separately and that Jacoco does not wait for them to finish to pick up the report.

All you need to do though is to downgrade to 6.3 and wait for a fix

Configure Sonar

You want to continue reading if you have your Jacoco reports ready and you want to be able to automate the visualisation and you would like to use the static analysis that Sonar offers.

This section assumes you know how to setup the server side and you know a little about Sonar.

You may again configure sonar in a separate gradle file, such as sonar.gradle and put it next to jacoco.gradle and not to forget, add “ apply from” to the main build.gradle file.

Add a new dependency in your module’s gradle file

We still use the 2.7.1 version, but I think it is safe to update to 2.8.

Then add this at the bottom (or in your newly created sonar.gradle file)

The pasted code snippet should work for all Sonar plugin versions, although some of the parameters may be deprecated.

Источник

Измерение покрытия кода тестами в Android с помощью JaCoCo

С тех пор как эта возможность появилась в Android Gradle плагине версии 0.10.0 было написано много статей об измерении покрытия кода тестами (test coverage) — и я не испытываю никаких иллюзий по этому поводу. Однако, что меня раздражает, так это необходимость заглядывать в несколько таких статей и даже в документацию Gradle прежде чем вы получите полностью работающее решение. Так что вот, еще одна статья которая попытается это исправить и сберечь ваше время.

Читайте также:  Как установить навител китайский андроид

Постановка задачи

Имеется Android проект с модульными тестами (unit tests), и мы хотим создать отчет о покрытии кода для выполненных тестов. Решение должно поддерживать различные режимы сборки (build types) и вариации продукта (product flavours).

Решение

Решение состоит из несколько частей, поэтому давайте рассмотрим его по шагам.

Включите сбор данных о покрытии кода

Вам нужно включить поддержку сбора данных о покрытии кода тестами для режима сборки (build type) в котором вы будете выполнять тесты. Ваш build.gradle должен содержать следующее:

Настройте JaCoCo

Хотя всё из этого раздела можно было бы поместить в build.gradle , такой «навесной монтаж» сделает ваш сценарий сборки не читаемым, поэтому я рекомендую поместить всё это в отдельный сценарий сборки, а затем импортировать.

Мы начнем настройку JaCoCo с создания файла jacoco.gradle в корневом каталоге проекта. Можете создать его в любом месте где пожелаете, но держать его в корневом каталоге проекта позволит легко на него ссылаться из всех подпроектов.

Самая простая часть — импорт JaCoCo:

Обратите внимание, что вам не нужно объявлять какие-либо зависимости чтобы использовать плагин «jacoco» — всё что нужно подключит плагин Android.

Чтобы проверить какая версия последняя, поищите org.jacoco:org.jacoco.core в jCenter, но обновляйте осторожно — самая последняя версия может оказаться пока еще несовместимой, что может привести к каким-нибудь странностям, например к пустому отчету.

Следующий шаг это создание задач Gradle (Gradle tasks) для всех вариаций продукта и режимов сборки (на самом деле вы будете тестировать только отладочную сборку (debug), однако очень удобно иметь такую возможность для любой специальной конфигурации отладочной сборки).

Обратите внимание что collect в Groovy получает на вход список, вызывает функцию с каждым элементом списка, а результаты возвращает в новом списке. В данном случае на вход поступают списки объектов «режим сборки» и «вариация продукта» которые преобразуются в списки их названий.

В угоду проектам в которых не заданы вариации продукта мы добавим пустое имя:

Теперь мы можем вот так пролистать их, что по существу является вложенным циклом в Groovy:

Самая важная часть — то, что мы поместим внутрь цикла, поэтому давайте рассмотрим это более подробно.

Сначала мы подготовим имена задач с правильной расстановкой заглавных букв:

  • sourceName – название источника сборки (build source name), н-р: blueDebug
  • sourcePath – путь к исходным кодам сборки (build source path), н-р: blue/debug
  • testTaskName – задача для выполнения тестов от которой будет зависеть задача измерения покрытия кода, н-р: testBlueDebug

Вот как мы их определяем:

Теперь задача, как она выглядит на самом деле:

Вы могли встречать похожий код в других статьях про JaCoCo, поэтому надеюсь, что большая его часть понятна без объяснений.

Части заслуживающие дополнительного внимания:

  • classDirectories – в «excludes» вы можете перечислить шаблоны для исключения из отчета; это может быть сгенерированный код (класс R , код внедряющий зависимости и т.д.) или что-угодно, что вы захотите игнорировать
  • reports – разрешает HTML и/или XML отчеты, в зависимости от того, нужны ли они для публикации или для анализа, соответственно.

Вот и всё о jacoco.gradle , поэтому вот полное содержимое файла:

В заключение вам нужно импортировать этот сценарий сборки в ваш сценарий в app как-то так:

(Обратите внимание: Здесь подразумевается, что jacoco.gradle расположен в корневой директории вашего проекта, как было описано выше)

Вот и всё! Вы можете убедиться, что задачи создаются, выполнив gradle tasks и поискав в секции «Reporting» что-то похожее на следующее:

Чтобы создать отчет, выполните gradle testBlueDebugUnitTestCoverage и вы найдете его в «build/reports/jacoco/testBlueDebugUnitTestCoverage/» .

Источник

Get Beautiful Coverage Reports in your Android Projects!

Alejandro Vidal Rodriguez

Jun 26, 2018 · 4 min read

Читайте также:  Changing device location android

There are several steps you can take to improve the quality of your code:

  • Linter check highlights on IDE
  • Enforce a correct and clean architecture
  • Write unit tests for your business logic
  • Write the test before implementation

But how can you track your code coverage in an easy and beautiful way?

We can now get coverage (on Android Studio) by: right clicking in our project → Run Tests with Coverage. This will output our code coverage metrics.

This will then output a report with our current coverage. After a few clicks you’ll find your package:

To avoid clicking around you can define a run/debug configuration under Android JUnit to specify your package and select a few include/exclude options:

B u t how we can exclude our data-binding classes, our activities, and things that our unit test coverage should not track? We want to have a metric that we care about, is something to keep an eye on, and that will keep our code with at least 60% of coverage.

Our old friend JACOCO (java code coverage) can help us get something easy to run, configured, and that can even send reports to our SonarQube to keep track of our code quality.

So, let’s add our dependencies:

When we add the JACOCO plugin our unit tests will be inspected, and JACOCO will output a .exec file with all the information regarding our coverage.

We also want specific reports that are readable and can give us feedback really fast, so let’s make a report task for our code with our exclusion rules for Android:

We will not unit test anything regarding the OS or UI, which means that we do not have any business logic in our activities, fragments, etc.

Our coverage task depends on our tests, which will change their names depending on the flavors we defined for our project.

When the test runs, the .exec will be generated. Then, it will be used as input for our report task, will output xml files that we can use on our CIs, and an html website for human readable results.

The last task is just a shortcut, execute ./gradlew getCoverage and then the test will run, a report will be generated, and the website will open with your results! 😎

Cool! What if we want to use those same rules so that our SonarQube reports use the same configuration that we used to get our nice coverage report website? We probably want to exclude the files that we are not focusing on from our SonarQube report in the coverage section, but we still want SonarQube to run the linter, bug checks, etc.

That’s what the sonar.coverage.exclusions property is for and that’s why we defined our exclusion array with a wildcard in the extension. This way we can iterate on it for this property and can match both .java and .class files.

Bam! A task that can be run by our CI (after the .exec is generated) which will give us a nice history of our code coverage in our SonarQube report.

You can even enforce minimum coverage in your JACOCO task in your gradle tasks!

How do you enforce your code coverage? Are there any rules you follow to keep your business logics tested and secure outside of the UI components? Let me know in the comments! Happy coding!

Alejandro (Alex) Rodriguez is the Engineering Director at the TribalScale Dubai office. For 8+ years, Alex has been delivering mobile apps and backend solutions for companies all around the world. He’s worked in Telefonica R&D’s mobile department in Spain, a search engine company in San Francisco, NFC payment solutions in the Netherlands, and is now helping TribalScale’s engineering team build clean efficient software in Dubai. Alex is passionate about architecture, clean code, process, and people.

Источник

Оцените статью