I am having problem to find documentation how could I solve that case.
I am capable of launching small/medium/large tests with:
./gradlew spoonSmall
./gradlew spoonMedium
./gradlew spoonLarge
Or launching specific tests with usage of this setup:
spoon {
(...)
if (project.hasProperty('spoonClassName')) {
className = project.spoonClassName
if (project.hasProperty('spoonMethodName')) {
methodName = project.spoonMethodName
}
}
}
I can launch specific file:
./gradlew spoon -PspoonClassName=com.package.tests.MyTest;
What I am interested in is a possibility to launch all tests located in:
./gradlew spoon -PspoonClassName=com.package.tests
package. Either method is fine. Some parameter to bash console or maybe way to create my own annotation and launch by something like ./gradlew spoonMyTests.
I am grateful for suggestions/help.
From the official docs:
There are numerous ways to run a specific test, or set of tests. You
can use the Spoon --size, --class-name or --method-name options, or
you can use the --e option to pass arguments to the instrumentation
runner, e.g.
--e package=com.mypackage.unit_tests
The following command should work when executing Spoon directly from command line (not from the gradle task)
java -jar spoon-runner-1.1.9-jar-with-dependencies.jar \
--apk ExampleApp-debug.apk \
--test-apk ExampleApp-debug-androidTest-unaligned.apk \
--e package=com.package.tests
You need to find a way to pass this extra param to the Spoon gradle plugin.
UPDATE
From the official doc of Spoon Gradle plugin:
Custom instrumentation arguments
Use the instrumentationArgs property on spoon extension to pass custom
parameters to your tests:
spoon { instrumentationArgs = ["foo=bar", "name=value"] }
In your case, this should look like the following:
spoon {
instrumentationArgs = ["package=com.package.tests"]
}
Related
I have a Flutter application that also has some Rust code, and they communicate via flutter_rust_bridge. There are already some tutorials talking about how to build such an app. However, they require me to manually trigger cargo build (or similar commands) and flutter run separately. You know, this is quite cumbersome, and if I forget to execute cargo, or that command fails, I run the risk of building a Flutter app with an old binary. Therefore, I wonder how I can automate that process. Thanks!
Android
Add the following to your build.gradle
[
new Tuple2('Debug', 'debug'),
new Tuple2('Profile', 'release'),
new Tuple2('Release', 'release')
].each {
def taskPostfix = it.first
def profileMode = it.second
tasks.whenTaskAdded { task ->
if (task.name == "javaPreCompile$taskPostfix") {
println "hello let ${task.name} dependsOn cargoBuild$taskPostfix"
task.dependsOn "cargoBuild$taskPostfix"
}
}
tasks.register("cargoBuild$taskPostfix", Exec) {
println "hello executing doLast for task cargoBuild$taskPostfix"
commandLine 'sh', '-c', "build-your-rust-code"
}
}
where build-your-rust-code is the command you use to build your Rust code. (For example, I use fastlane to wrap it (of course you can use others) and I put that in a rust folder, so I just call cd $projectDir/../rust/fastlane && bundle exec fastlane build_android profile:$profileMode.)
iOS
Method 1
The most manual way is as follows. Go to Build Phases, click + button and choose New Run Script Phase. Then enter the script you want to run to build your Rust code. (For example, for myself, I use Shell /bin/sh and call some fastlane commands which executes the actual commands.)
Method 2
A more automated approach is to use the CocoaPod files, which will automatically help you set up everything. For example, I add:
s.script_phase = {
:name => 'Compile Rust',
:script => your-script-to-compile-it,
:execution_position => :before_compile,
:shell_path => '/bin/sh'
}
(For example, my script is %q{env -i HOME="$HOME" PROJECT_DIR="$PROJECT_DIR" CONFIGURATION="$CONFIGURATION" /bin/bash -c 'source ~/.bashrc && cd $PROJECT_DIR/../.symlinks/plugins/vision_utils/rust/fastlane && LC_ALL= LANG=en_US.UTF-8 bundle exec fastlane build_ios profile:$CONFIGURATION'}. Notice that, at least in my case, I have to create a brand new shell. Otherwise the opencv in my Rust complains and fails to compile. But you may not have this problem if your Rust code does not contain c++ things.)
(Q&A style answer in order to help people who face the same situation as me, especially when not familiar with Android and iOS)
I am facing a problem with Robolectric library. I am writing unit tests using Robolectric, it's working locally but when I merge my code, it crashes on pipeline(remotely).
I am using 'org.robolectric:robolectric:4.0.2'
It fails by only adding this line to my test class: #RunWith(RobolectricTestRunner.class)
And the exception is:
FAILED
org.apache.tools.ant.BuildException
Caused by: org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException
I had the same issue: Robolectric was working fine locally, but once pushed to Jenkins the gradle task to execute the tests fails.
You can execute the gradle task to run the tests with -i -d flags to see more debug output.
./gradlew -i -d test
For me this revealed that Jenkins was unable to download Robolectric dependencies:
13:58:43 13:58:42.904 [DEBUG] [TestEventLogger] com.my.package.Test > my_test_case STANDARD_ERROR
13:58:43 13:58:42.904 [DEBUG] [TestEventLogger] Downloading: org/robolectric/android-all/9-robolectric-4913185-2/android-all-9-robolectric-4913185-2.jar from repository sonatype at https://oss.sonatype.org/content/groups/public/
I could solve it by telling gradle to use our corporate proxy when running on Jenkins. One way to achieve this would be to add the following to your gradle.properties:
systemProp.http.proxyHost=http://proxy.host
systemProp.http.proxyPort=3128
systemProp.https.proxyHost=http://proxy.host
systemProp.https.proxyPort=3128
---- EDIT ----
Actually I found a cleaner solution for my use case then configuring a proxy: Robolectric offers a way to configure the repository it uses during runtime (see http://robolectric.org/configuring/). This way I was able to tell it to use our corporate repository.
android {
testOptions {
unitTests.all {
systemProperty 'robolectric.dependency.repo.url', 'https://local-mirror/repo'
systemProperty 'robolectric.dependency.repo.id', 'local'
}
}
}
In my case the issue was (./gradlew -i -d testDebug printed it):
Caused by:
org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException: Missing:
----------
1) org.robolectric:android-all:jar:10-robolectric-5803371
...
Robolectric tried to fetch a dependency from the remote repository, but it couldn't.
As the output suggests, I have:
Manually downloaded org.robolectric:android-all:jar:10-robolectric-5803371 jar from the Maven repository.
Located it in /home/user/jars
Installed Maven on my machine: sudo apt install maven
Linked the jar with Robolectic: mvn install:install-file -DgroupId=org.robolectric -DartifactId=android-all -Dversion=10-robolectric-5803371 -Dpackaging=jar -Dfile=/home/user/jars/android-all-10-robolectric-5803371.jar
Now ./gradlew testDebug works fine.
Also check the issue on Github, maybe there will be some more useful information for you.
As #Christian.D said, Robolectric tries to download dependencies from external repository, but we need that it uses internal one. Below the fix:
1) Create a custom RobolectricTestRunner:
public class CustomRobolectricRunner extends RobolectricTestRunner {
public CustomRobolectricRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
static {
RoboSettings.setMavenRepositoryId("my-nexus");
RoboSettings.setMavenRepositoryUrl("your_custom_url");
}
}
2) Annotate your test class:
#Config(manifest = Config.NONE)
#RunWith(CustomRobolectricRunner.class)
Good coding!
I have to following gradle code:
testOptions {
unitTests.returnDefaultValues = true
unitTests.all {
// All the usual Gradle options.
jvmArgs '-XX:MaxPermSize=1024m'
}
execution 'ANDROID_TEST_ORCHESTRATOR'
}
And I am using Android test orchestrator, but I makes my UI tests take a lot of time to run. So I would like to be able to request for orchestrator in the command line like:
./gradlew androidConnectedCheck --orchestrator
So I can controll when to use orchestator. Is it possible to do that with gradle?
Edit:
I am not interested in using a gradle variable in my code (in Java or Kotlin) I would like to create a conditional test configuration accordingly with my command line
./gradlew androidConnectedCheck -Porchestrator
And in gradle, you can do:
def orchestrator = project.hasProperty('orchestrator')
orchestrator will be true if it was passed as an arg. This uses the project-prop built into gradle command line.
I am interested in how to run Espresso tests from command line (gradle task) individually (run group/suite tests then close app and then run another group/suite of tests).
Found that it is feasible to implement JUnit Test Suites but do not really understand how does it looks like under the hood in a context of instrumentation tests. Does it starts separate processes per Test suite? There is sample application on Github but how to execute it from terminal?
Another interesting discovery is Sharding tests. However, it one sentence documentation.
May be somebody can share with any experience of running Espresso tests individually.
Most of this is documented as part of AndroidJUnitRunner: https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html
The key piece that is missing is how to pass those parameters via Gradle. You can do that by specifying the options at the commandline as such:
./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=*The full name of your test suite goes here*
I would recommend using the Spoon library to run your tests individually or in parallel on multiple devices. You can either use the jar file or use the Spoon gradle plugin mentioned on the same page. Both of them have adequate documentation to help you set it up.
You can also use Spoon to run an individual test and the command would look something like this:
./gradlew yourSpoonTaskName -PspoonClassName=com.yourPackageName.blah.ClassName
-PspoonMethodName=methodName
In order to know what yourSpoonTaskName is run ./gradlew tasks.
Also, in your build.gradle file add the following spoon configuration:
spoon {
// for debug output
debug = true
// To grant permissions to Android M >= devices
grantAllPermissions = true
// for sharding
/*
this will execute tests in parallel on multiple devices.
*/
shard = true
// Add this to run a specific test class & method
if (project.hasProperty('spoonClassName')) {
className = project.spoonClassName
}
if (project.hasProperty('spoonMethodName')) {
methodName = project.spoonMethodName
}
}
If you are not interested in Spoon and just want a simple solution, then use the following command to run an individual test:
am instrument -w -r -e class com.packageName.blah.TestName#methodName com.packageName.blah.YourIntrumentationRunnerName
You can easily determine these values if you right click the test name in AndroidStudio and run it. In the console, you will see the entire command being printed when the test is bring run.
Is there a way to run a specific Android instrumentation unit test using Gradle? I've tried
gradle -Dtest.single=UnitTestName connectedInstrumentTest
but it seems to run all the tests in the package.
Using test.single appears to be deprecated. The new correct way to do this is
./gradlew :<module>:test --tests <pattern>
where <pattern> could be something like:
com.example.MyTest to run all test methods in com.example.MyTest
*MyTest to match every method in every class whose name ends with MyTest
*.MyTest.myMethod to run a specific test method in class MyTest in any package
If you have a multi-project build, make sure to give the module path before the test task; otherwise you'll get a misleading error message when it searches for your test pattern in every subproject.
None of this is documented on the Gradle site anywhere I could find it.
This works if you're using an instrumentationTestRunner:
./gradlew test -Pandroid.testInstrumentationRunnerArguments.class=<pkg>.YourClassName
Using gradle 2.10 and android gradle plugin 2.0.0-beta2.
Since you know what test(s) you want to run, you probably know which module / flavor to use too. You can help Gradle out by specifying the exact module and Gradle task. So if your test is in the app module and you want to test the debug flavor:
./gradlew app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=<pkg>.YourClassName
You can get even more fancy with the tests_regex argument instead:
./gradlew app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.tests_regex=PartialClassName*
./gradlew app:connectedDebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.tests_regex=partialMethodName*
The pattern is -D<testTaskName>.single=<TestClass> so in your example it should be:
gradle -DconnectedInstrumentTest.single=UnitTestName connectedInstrumentTest
NOTE: This answer is outdated. You should use the --tests switch in the latest versions of Gradle. (see other answers for an explanation)
Since Android gradle plugin 1.1.0-rc1, one can run single test class using --tests flag by executing:
./gradlew app:testDebug --tests=com.example.MyTest
See http://tools.android.com/tech-docs/unit-testing-support#TOC-Running-from-Gradle
You gotta check this out.
https://github.com/JCAndKSolutions/android-unit-test
I made an issue in this github repository, and this guy solved my problem and upload to maven, so in my build.gradle file I use this plugin.
Instructions are written in his repository. you can easily follow it.
After using this android-unit-test plugin, I can use like
../gradlew -Dtest.single=SomeTest test
or
../gradlew -Dtest.single=SomeTest clean check
Now it's working and I could only run the specific tests I want to
You should not forget to specify a build variant name after test property declaration like
-Dtest<buildVariantName>=<yourTestName>.
Like if you have a debug build type which gives you debug variant after compilation, then if you want to run a test only for this build variant you should declare a command like this:
./gradlew -DtestDebug=UnitTestName testDebug
Erdi's answer didn't work for me but I have a single parent for all my test classes so I was able to do this:
public abstract class BaseEspressoTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
//...
#Override
protected void runTest() throws Throwable {
if(getClass().getSimpleName().equals("MyTestClassName")) {
super.runTest();
}
}
//...
}
This executes only MyTestClassName. We can extend it further to execute only specific test method (or methods):
public abstract class BaseEspressoTest<T extends Activity> extends ActivityInstrumentationTestCase2<T> {
//...
#Override
protected void runTest() throws Throwable {
if("MyTestClassName".equals(getClass().getSimpleName())
&& "testMethodName".equals(getName())) {
super.runTest();
}
}
//...
}
the Gradle command does not work for me.
I used below mentioened adb command.
for this you need to build your apk first.
adb shell am instrument -w -r -e package -e debug false .debug.test/android.support.test.runner.AndroidJUnitRunner