Testing multiple build variants simultaneously - android

I created a Test case (using Espresso 2) for an application with multiple Flavors and I would like to run that Test for all the flavors simultaneously (or at least one after the other). Is that possible? At the moment I am only able to run the test for the current Build Variant selected, so I have to manually change the Build Variant and run the test again, one by one.
Thank you very much.

If you know the names of the gradle tasks that install your tests you can run this from the root of your project in the terminal:
./gradlew install{VariantName1, VariantName2, VariantName3}Test
This assumes you have a module build.gradle file with variants set up according to the guide. So something along these lines:
apply plugin: 'com.android.application'
android {
...
flavorDimensions "myFlavorDimension"
productFlavors {
VariantName1 {
...
}
VariantName2 {
...
}
VariantName3 {
...
}
}
...
}
dependencies {
...
}
You can find these gradle task names either in Android Studio in the Gradle Tab (right side of GUI) under you moduleName->Tasks->install
Or you can find them in the terminal with:
./gradlew tasks | grep install
I'm sure there is some Regex that could grab only the ones of interest programmatically as well, but I'm not a regex buff. If you want to leave a comment with something that would work, I'd be happy to edit and add later.

Related

android getting coverage on local unit tests

I've been trying to get the code coverage for my local unit tests and haven't been successful.
Here's a reference on what I mean by local unit tests.
https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
To run my unit tests, I use the following gradle command.
./gradlew clean testDebugUnitTest
This task will run the unit tests but when I view the jacoco file that gets generated (testDebugUnitTest.ec) in "build/jacoco" folder, it always shows an empty coverage.
I've enabled the coverage in my build.gradle file as follows.
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
but that doesn't seem to help. Is there something that I am missing?
Note that if I run the local unit tests through Android Studio, everything works fine. I clicked on my "tests" module and click on "Run tests with coverage".
So, I found out the answer to my own question. Oddly enough, it looks like running "testDebugUnitTest" with the "testCoverageEnabled" flag set is the correct way to do it.
However, since apparently gradle's jacoco version is different than the jacoco version that is running in Android Studio and my CI system (Jenkins), it wasn't able to be viewed due to some backwards compatibility issue in jacoco.
To fix the issue, I set my jacoco version in gradle to the same one in my Android Studio (Intellij) and Jenkins.
jacoco {
toolVersion = '0.7.0.201403182114'
}
I put the code above in my build.gradle file.
I've had to solve the problem myself and I was actually expecting the default gradle plugin will have support for code coverage for local unit tests. Unfortunately, out of the box, there is no support for this, even on android gradle plugin version 3.0.1.
Fortunately, however, there is a simple third-party plugin we can use to generate jacoco test reports: gradle-android-junit-jacoco-plugin
To use it, you need to register this plugin's repository and classpath into your root-level build.gradle. Your build.gradle file might look different, but this is what worked for me:
buildscript {
repositories {
// ... there may be other repositories here
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
// ... other classpaths here too
classpath "gradle.plugin.com.vanniktech:gradle-android-junit-jacoco-plugin:0.11.0"
}
}
And to generate the report, one can simply do this:
./gradlew jacocoTestReportDebug
The output will be in one of your modules build folder, for example:
your-module/build/reports/coverage/debug/index.html
Note I verified this working on android gradle plugin 3.0.1.
For reference, my source is this answer from Niklas, creator of the plug-in: https://stackoverflow.com/a/33064500/390718

How to get build variant output directory

I need to run some tasks that occur after an Android project's assemble* task finishes. In particular, these tasks need to know what was the output directory for all the compiled classes for a particular build variant. How do I retrieve the output directory for an assembleFlavor1Debug task?
My current workaround is something like this (although this workaround presents problems of its own, like not being able to find the assemble tasks even though it's been placed after the android configuration block):
android.buildTypes.all { theBuildType ->
android.productFlavors.all { theFlavor ->
String capitalizedType = ... //Type name with first letter capitalized
String capitalizedFlavor = ... //Flavor name with first letter capitalized
...
project.tasks["assemble${capitalizedType}${capitalizedFlavor}"].configure {
doLast {
project.ext.variantOutput = "build/intermediates/classes/${theFlavor.name}/${theBuildType.name}"
}
}
}
}
EDIT #1: I was able to fix my workaround. The major issue was that the Android assemble* tasks (assembleProdDebug, assembleProdRelease, etc.) were not yet created on the project, even though configuration was occurring after the Android configuration block. I was able to get the additional configuration on the assemble* tasks done by enclosing the entire code snippet above into a gradle.taskGraph.whenReady {...} block, but this did mean I lose out on the ability to continue configuring the dependency graph. Fortunately, not being to configure dependencies in my particular case was not a major loss; all I needed was the ability to record the last assembled build type and product flavor.
I'd also like to note that this behavior is with version 1.0.0 of the Android Gradle plugin. Although I have not checked, the absence of these Android tasks might not occur on newer versions of this plugin.
EDIT #2: So I've also tried version 1.3.0 of the Android Gradle plugin. I'd also like to note that this is the LIBRARY Android plugin, and not the application plugin (I suspect these missing assemble* tasks are not generated during project configuration for the application plugin as well, however).
You might want to try instead of wrapping the entire thing with gradle.taskGraph.whenReady try using afterEvaluate closure. The tasks should exist after the project is evaluated.
This means your closure would run at the end of the configuration phase and before the execution phase. At this time all tasks would have to be registered.
afterEvaluate { project ->
// do work on `Project` object just like normal
project.android.buildTypes.all { theBuildType ->
...
}
}
ref: https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#afterEvaluate(groovy.lang.Closure)

Conditionally include project in gradle build

Scenario: We have an Android app with a few different optional components that we would like to be able to include/exclude depending on customer needs and licensing. Is it possible to include specific projects based on a build parameter and without creating all permutations as build flavors?
./gradlew assembleRelease -PincludeFeatureA=true -PincludeFeatureB=false
I thought I could do something like this in dependencies:
dependencies {
if(includeFeatureA){
compile project(':featureAEnabled')
} else {
compile project(':featureADisabled')
}
}
But that doesn't seem to work.
Update: Considering the number of toggle-able features, using explicit build variants for every permutation is cumbersome.
For example, given 3 toggle-able features, I do not want to have to build flavors like this:
Feature1
Feature1-Feature2
Feature1-Feature3
Feature1-Feature2-Feature3
Feature2
Feature2-Feature3
...
The solution for my scenario was to move the if statement out of the dependencies:
Assuming the command line:
gradlew assembleRelease -PincludeFeatureA
At the beginning of the project build.gradle, I include this:
def featureA_Proj=':featureA_NotIncluded'
Then I have a task like this:
task customizeFeatureA(){
if(project.hasProperty('includeFeatureA')){
println 'Including Feature A'
featureA_Proj=':featureA'
}
}
Finally, under dependencies, I just include:
dependencies{
include(featureA_Proj)
}
Use Build Variants. You can enable or disable dependencies on the projects based on them You can even use separate assets or source code with them.
Check out the settings.gradle file, it can be used to indicate which all projects to build, here you might be able to read the settings set and use those.
See
https://docs.gradle.org/current/userguide/build_lifecycle.html
https://docs.gradle.org/current/userguide/multi_project_builds.html
That might help.

How to add a new source directory to an Android Studio project?

So ultimately I'm trying to separate my integration tests from the unit tests in an Android Studio project. I've found a few resources on the subject:
http://selimober.com/blog/2014/01/24/separate-unit-and-integration-tests-using-gradle/
https://blog.safaribooksonline.com/2013/08/22/gradle-test-organization/
Separating integration tests from unit tests in Android Studio
All these seem to indicate that the way to go is to create a new sourceSet for the integration tests, and then to create a new test task which builds and runs the tests in that source set. I can't get past the first step of creating a source set which is recognized by Android Studio.
Here's what I have within app/build.gradle, which builds without errors, but does not result in an integrationTest source root I can add classes to:
android{
...
sourceSets{
integrationTest {
java.srcDir('src/integrationTest/java')
}
}
}
My questions are:
Where precisely do I have to add the sourceSets block? In build.gradle? in app/build.gradle? In app/build.gradle inside the android block?
Once I've added my source set in he right place using the correct syntax, is this sufficient for Android Studio to detect and present it in the UI along side the main and test sources, or are there additional steps?
edit:
I've attempted to follow the instructions in marius' answer, but integrationTest isn't showing up in my build variants. Here's what I'm seeing:
This is enough:
android{
...
productFlavors{
integrationTest {
}
}
}
Regarding your 1st question: The productFlavors block should be in your app/build.gradle, inside android block.
Regarding your 2nd question: Once you add this to your build.gradle file, you also need to create your folders /src/integrationTest and /src/integrationTest/java . Once that is done, sync your gradle files and choose your new Build Variant from the Build Variant window, in order for the IDE to detect it as the active source folder.

How to do Integration Testing on Android with the new Gradle Build System?

Our Android app needs automated testing, and our group is using Robotium to handle that for us. This is no problem for unit tests, but we're also writing a set of end-to-end integration tests to exercise not only the client by the back-end servers as well. I've got some tests that do this, but if possible, I'd like to break them out separately from the unit tests so that our continuous integration builds don't require a live server to be running in order to complete.
We're using the shiny new Gradle build system. I'm wondering if I could do something like a test-only flavor or a subproject that depends on the parent APK to make it go. I tried making this work with a separate project altogether using the Robotium instructions for testing a source-less debug APK, but it didn't work. Maybe because I was on real hardware and not an emulator. I've had poor luck with the emulator, even with the hardware acceleration installed.
Any advice, or should I just hold my breath and roll with my builds requiring the integration server to be available when builds are happening?
According to their Maven instructions all you need to do is add robotium-solo as a compile dependency.
repositories {
mavenCentral()
}
dependencies {
instrumentTestCompile 'com.jayway.android.robotium:robotium-solo:4.2'
}
This will ensure you have the robotium-solo.jar file in your classpath. Then define your tests in the src/instrumentTest directory and run gradle build. See if that works?
I'll help where I can, as we converted from maven to gradle about a year ago.
*EDIT OP wanted the tests to run separately from a gradle build, so the solution is to specify a custom source set like so:
sourceSets {
integrationTest {
// Gives you access to the compiled classes in your tests
compileClasspath += main.output
runtimeClasspath += main.output
}
}
dependencies {
integrationTestCompile 'com.jayway.android.robotium:robotium-solo:4.2'
}
// To run the tests: ./gradlew integrationTest
task integrationTest(type: Test) {
testClassesDir = sourceSests.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
Note: I don't have the android SDK installed on this computer. If main.output does not work try it with andriod.sourceSets.main.output and see if that works.

Categories

Resources