I created a custom Gradle task for running from terminal in a separate file named feature.gradle, based on this answer and Gradle docs
task("withFeature", JavaExec::class) {
group = "myCustomTasks"
main = "com.example.calculator"
classpath = sourceSets["main"].runtimeClasspath
args(feature)
}
and register task in Gradle
tasks.register("withFeature")
feature is a property (string) that I want to pass into test (for now it's unit test, but later it would be android UI test)
#Test
fun getPackArgs() {
val property = System.getProperty("feature")
Assert.assertEquals("default", property)
}
But when i write next command, where -Pfeature=default is what i wants to pass into code
./gradlew test withFeature -Pfeature=default
test fails, and System.getProperty("feature") is null :
expected:<default> but was:<null>
Expected :default
Actual :null
Can anyone elaborate what i am doing wrong while running task with argument, which should pass into test package ?
Thanks in advance
Related
I have to create a gradle custom task in KOTLIN with different args as input.
So based on the args, the custom task should run other tasks.
e.g: I want to run:
./gradlew ci type=release distribution=true version=1.2.2
OR
./gradlew ci type=debug distribution=true version=1.2.2
This command should run tasks: clean, assembleRelease OR assembleDebug (based on type param) and also another task to distribute the artifact (already have this one) if the distribute param is true.
Question 1: Is there any way to create a custom task that runs other tasks based on external params?
Question 2: Is there any way to inject the args? (the above commands are not valid I think)
You can pass properties with -P command and here is an example.
task passP() {
if (customProp.equals("myProp")) {
println customProp
}
}
this will only print if you execute the following command Gradle -PcustomProp=myProp passP
Now that you can pass parameters, You can clean, assembleRelease OR assembleDebug according to the passed parameters.
There Are two ways you can achieve that.
First way :
Make a gradle custome task to execute another gradle command which do not look neat. but the code will look like this
task passP(type: Exec) {
commandLine("cmd", "/c")
if (customProp.equals("clean")) {
args "gradle clean"
}
}
This will execute a normal clean if you passed clean as a parameter.
The second way :
You would be using finializeBy keyword
You can call the 3 tasks according to the passed parameters.
The code will be something like this (not tested) :
task passP() {
if (customProp.equals("clean")) {
tasks.named("clean") { finalizedBy("passP") }
if (customProp.equals("debug")) {
tasks.named("assembleDebug ") { finalizedBy("passP") }
}
}
The first way work 100%, But am not sure about the second one, As am only used to use finalizedBy out side of the custom task scope.
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.
I added another source set, and a task of type test that uses that source set. I can execute the task and run the tests fine.
However, Intellij doesn't consider this src/newTests/java as tests. If I 'Mark directory as test sources' in the UI, it will forget it he next time build.gradle is synced. How do I make it remember this?
Try this:
android {
sourceSets {
test {
java.srcDir file('src/newTest/java')
}
}
}
Result:
I want to check whether an environment variable is set ONLY before running my unit tests in a Gradle build.
I've tried to use following type of code:
tasks.withType(Test) {
task ->
task.doFirst {
if (isEnvironmentVariableSet)
throw new RuntimeException("Environment variable XXX is not set")
}
}
Unfortunately this code always checks whether the environment variable is set, even when you are just doing ./gradlew build.
Presumably it's because this diagram shows that http://www.gradle.org/docs/current/userguide/img/javaPluginTasks.png
'test' tasks are always run, even when building.
However, if that is the case, why don't my unit tests get run when I do the ./gradlew build command? Perhaps they are run, but if they are, their failure/success is not reported. Can someone explain, and suggest the best way of doing the check I am looking for?
PS I am running an Android build.
I have 2 gradle tasks that i want to run after assembleRelease task.
task copyRequiredFilesToVersionControl(type:Copy) {
...
}
task ('versionControl') << {
...
}
If I configure order for these tasks as below tasks get never called...
copyRequiredFilesToVersionControl.dependsOn(assembleRelease)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
If i change order like;
assembleRelease.dependsOn(copyRequiredFilesToVersionControl)
versionControl.dependsOn(copyRequiredFilesToVersionControl)
Tasks are run at the beginning of document. So there is no file to copy and add to version control.
What is the best approach?
I have found method that called doLast. So i fixed my problem with it.
assembleRelease {
doLast {
tasks.versionControl.execute()
}
}
The best approach that I've found to date, has been to use the Ordering Tasks feature in Gradle : see http://www.gradle.org/docs/current/userguide/more_about_tasks.html for more documentation, currently section 15.5.
Basically, you have two rules available : MUST run after and SHOULD run after. I like the rule quite a bit, I use this to create zip archives of projects automatically. NOTE : you must still make use of the "dependsOn" to get proper execution if tasks that you need to have run in a particular order.