I want to run UI tests and unit tests on a project in CI (Jenkins Pipeline). The UI tests requires images and video to be on the test device / emulator. In the UI tests I request permission for storage read/write access so I can dump a few assets into the downloads folder, then at the end of the test suite I remove them.
When I run my tests on Jenkins (mac) permissions are not granted, no media transfers over, and all of my tests fail.
The project contains an app module and two in-house library modules.
Build
sh "./gradlew clean assembleRelease"
Unit Test
sh "./gradlew testReleaseUnitTest"
UI Test
sh "$ANDROID_HOME/emulator/emulator @my_sweet_emulator_name -no-boot-anim & $ANDROID_HOME/platform-tools/adb wait-for-device"
sh './gradlew connectedAndroidTest'
1) The CI build hangs on the implicit assembleDebugAndroidTest
task
2) If I run that task on the command line on my computer the tests will install however the permission is not granted to read/write storage so all tests fail due to not having any expected content on the device.
testBuildType "release"
How I'm granting permissions
@RunWith(AndroidJUnit4::class)
class MyMediaClassTest {
@Rule
@JvmField
val activityRule = ActivityTestRule(MainActivity::class.java)
@Rule
@JvmField
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule
.grant(android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
// tests and stuff
}
I have seen a short-term solution to manually copy all of my media assets into the emulator. But that doesn't seem right, this should be able to be automated.
The way it worked with me is by following the below steps:
Added the permissions in the AndroidManifest.xml
file of my app
module.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
And have tried executing the below instrumented test cases/class:
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Rule
@JvmField
val grantPermissionRule: GrantPermissionRule = GrantPermissionRule
.grant(android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
val rootDir = "/sdcard/"
@Test
fun testTargetContextPermission() {
val targetContext = InstrumentationRegistry.getTargetContext()
assertTrue("Not the target package",
!targetContext.packageName.endsWith(".test"))
assertTrue("Permissions not Granted", targetContext.checkSelfPermission(
android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
targetContext.checkSelfPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
val file = File(rootDir + "targetTest.txt")
if (file.exists()) {
file.delete()
}
assertTrue("File was not created", file.createNewFile())
val sdcard = File(rootDir)
assertTrue("sdcard is empty or file not found", sdcard.list().size != 0 &&
Arrays.asList<String>(*sdcard.list()).contains("targetTest.txt"))
}
@Test
fun testInstrumentationPermission() {
val instrumentationContext = InstrumentationRegistry.getContext()
assertTrue("Not the instrumentation package",
instrumentationContext.packageName.endsWith(".test"))
assertTrue("Permissions not Granted", instrumentationContext.checkSelfPermission(
android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED &&
instrumentationContext.checkSelfPermission(
android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
val file = File(rootDir + "instrumentationTest.txt")
if (file.exists()) {
file.delete()
}
assertTrue("File was not created", file.createNewFile())
val sdcard = File(rootDir)
assertTrue("sdcard is empty or file not found", sdcard.list().size != 0 &&
Arrays.asList<String>(*sdcard.list()).contains("instrumentationTest.txt"))
}
}
Both test cases returned with success. Upon changing rootDir
to "/"
, the tests failed since the /
directory is a read-only which is expected.
The idea behind having two test cases is to test the different Context
which the tests could retrieve at runtime. The testTargetContextPermission
uses the app Context
which does not have it's package name or application id ending with .test
. While the testInstrumentationPermission
uses the instrumentation app Context
which does have it's package name or application id ending with .test
. I thought that permissions need to be defined in each of their AndroidManifest
s but turns out that defining the permissions for your app
AndroidManifest
only will automatically give the same permissions to the Instrumentation package as well.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With