Issue
I'm writing a Room database into my getFilesDir() folder. (Writing the database onto the removable SD card is apparently going to require some major research!)
When I manually run my app, I want to write some records and leave them in the database, so I don't need to keep writing them again. When I run my tests, I switch the database name from "*.dat" to "_test.dat" (think Ruby on Rails's or Django's "environments" system). The tests are free to erase records.
This system works when I manually tweezer each test in Android Studio to run it. But when I run everything in a batch, in gradlew
, something erases the "*.dat" version of the database. This means I must constantly manually repopulate the database, each time I manually test.
What inside gradlew
is erasing the contents of my getFilesDir() folder? And how (without figuring out how to use "external" storage), do I defeat it?
Code samples available on request, but it's all just generic stuff. Switching to getExternalFilesDir() does not fix the problem. StackOverflow said to try ./gradlew test connectedAndroidTest -x uninstallAndroidTest
, but there's no uninstallAndroidTest
task.
The top level build.gradle
:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
tasks.withType(Test) {
testLogging {
exceptionFormat "full"
events "started", "skipped", "passed", "failed"
showStandardStreams true
}
}
The app/build.gradle
:
apply plugin: 'com.android.application'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.allflat.planarinfinity"
minSdkVersion 26
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// packagingOptions {
// exclude 'META-INF/DEPENDENCIES'
// exclude 'META-INF/LICENSE'
// exclude 'META-INF/LICENSE.txt'
// exclude 'META-INF/license.txt'
// exclude 'META-INF/NOTICE'
// exclude 'META-INF/NOTICE.txt'
// exclude 'META-INF/notice.txt'
// exclude 'META-INF/ASL2.0'
// exclude 'META-INF/INDEX.LIST'
// }
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
testImplementation 'junit:junit:4.12'
// testImplementation 'org.mockito:mockito-core:2.19.0'
testImplementation 'androidx.arch.core:core-testing:2.1.0'
androidTestImplementation 'org.powermock:powermock-core:2.0.2'
androidTestImplementation 'org.powermock:powermock-module-junit4:2.0.2'
androidTestImplementation 'org.powermock:powermock-api-easymock:2.0.2'
androidTestImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.2-alpha02'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0-alpha02'
androidTestImplementation 'com.android.support.test.espresso:espresso-contrib:3.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
// androidTestImplementation 'androidx.test.platform.app:'
implementation 'androidx.room:room-runtime:2.2.0'
annotationProcessor 'androidx.room:room-compiler:2.2.0'
testImplementation 'androidx.test:core:1.2.0'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'org.easymock:easymock:4.0.2'
// androidTestImplementation 'org.mockito:mockito-core:2.19.0'
}
It's the 'uninstall' in here:
Could someone take it out? It's annoying everyone.
Solution
Per the winning entry here...
Run connectedAndroidTest and skip uninstall
...the answer is to write a Rakefile
containing:
task default: [ :unit_test_and_install, :espresso_test ]
task :unit_test_and_install do
sh './gradlew --console=verbose test installDebug installDebugAndroidTest'
end
devices = `adb devices`
serial_numbers = devices.split("\n")[1..-1].map{|q| q.split("\t")[0] }
task :espresso_test do
threads = serial_numbers.map do |sn|
Thread.new do
sh "adb -s #{sn} shell am instrument -w -r -e package com.mycorp.myapp -e disableAnalytics true " +
"com.mycorp.myapp.test/androidx.test.runner.AndroidJUnitRunner | tee #{sn}.txt"
end
end
threads.each &:join
serial_numbers.each do |sn|
grop = `grep "^OK .*tests" #{sn}.txt`
if grop == ''
sh "cat #{sn}.txt"
abort 'FAILURES on ' + sn
end
end
end
Then just enter $ rake
. All the tests run, while my manual-testing data and configurations all survive.
We need a Ruby Rakefile
, not a Makefile
, because we need to process the output and look for errors to successfully return either 0 or 1 to the environment. But adb etc
fails the rule "test faults are syntax errors," and does not propagate the correct exit value at fault time. I want my command line to abend and not commit broken code, so we stash the test outputs into SERIALNUMBER.txt files and then grep
them.
And we need threads, so many devices can test at the same time without waiting for each other.
Correctly detecting errors allows one to integrate in one line, $ rake && git commit -am 'the same comment every time' && git push
. If there were any errors, they display on the console, and the git commit
does not happen.
And we need Makefile
-style processing, because if any command fails we need to stop processing, following the rule "test faults are syntax errors."
(A new bug is at Espresso test fault time we no longer get the message saying where is the HTML output file, but because the error itself is in the spew this is less of a problem.)
Another bug: If I have two tablets hooked up via USB debugging, I get error: more than one device/emulator
, which is utterly bogus because ./gradlew test connectedAndroidTest
naturally works correctly on all devices... That's why the Rakefile
must find all the devices and then dispatch adb shell -s
to each one.
Please write any and all complaints about using a lowly Rakefile
to call gradlew
here: [__].
Answered By - Phlip
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.