android-junit5
android-junit5 copied to clipboard
Alternative method for GrantPermissionRule
The GrantPermissionRule works on JUnit4, but seems not working on JUnit5.
Is there an alternative method for this?
Code:
@Rule
public GrantPermissionRule rule = GrantPermissionRule.grant(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE
);
I'm running this test code on Android R physical device. Any help will be appreciated, thanks.
The direct replacement for JUnit 4's TestRule is the JUnit 5 Extension Model. In essence, you'd need to translate the behavior of the GrantPermissionRule into an extension, which you could then attach to your test with the @RegisterExtension annotation. Skimming over the rule's code, it looks like the extension for permissions would only need to implement BeforeAllCallback, but I'd need to investigate further to have a better guess here.
As an example of how to write an extension based on an existing rule, you could check out the ActivityScenarioExtension, which is the direct translation of AndroidX's ActivityScenarioRule.
Below is a first version of the JUnit5 implementation for the rule. I'll have to conduct some more tests with it, but it'll be likely shipped in the 1.3.0 release of the android-test-core library.
package de.mannodermaus.junit5
import android.Manifest
import android.os.Build
import androidx.test.internal.platform.ServiceLoaderWrapper.loadSingleService
import androidx.test.internal.platform.content.PermissionGranter
import androidx.test.runner.permission.PermissionRequester
import org.junit.jupiter.api.extension.BeforeEachCallback
import org.junit.jupiter.api.extension.ExtensionContext
/**
* The {@code GrantPermissionExtension} allows granting of runtime permissions on Android M (API 23)
* and above. Use this extension when a test requires a runtime permission to do its work.
*
* <p>When applied to a test class it attempts to grant all requested runtime permissions.
* The requested permissions will then be granted on the device and will take immediate effect.
* Permissions can only be requested on Android M (API 23) or above and will be ignored on all other
* API levels. Once a permission is granted it will apply for all tests running in the current
* Instrumentation. There is no way of revoking a permission after it was granted. Attempting to do
* so will crash the Instrumentation process.
*/
public class GrantPermissionExtension
private constructor(
permissions: Set<String>,
private val granter: PermissionGranter = loadSingleService(PermissionGranter::class.java, ::PermissionRequester)
) : BeforeEachCallback {
public companion object {
@JvmStatic
public fun grant(vararg permissions: String): GrantPermissionExtension {
val permissionSet = satisfyPermissionDependencies(*permissions)
return GrantPermissionExtension(permissionSet)
}
private fun satisfyPermissionDependencies(vararg permissions: String): Set<String> {
val set = permissions.toMutableSet()
// Grant READ_EXTERNAL_STORAGE implicitly if its counterpart is present
if (Build.VERSION.SDK_INT >= 16 && Manifest.permission.WRITE_EXTERNAL_STORAGE in set) {
set.add(Manifest.permission.READ_EXTERNAL_STORAGE)
}
return set
}
}
init {
granter.addPermissions(*permissions.toTypedArray())
}
override fun beforeEach(context: ExtensionContext?) {
granter.requestPermissions()
}
}
Usage:
@RegisterExtension
public GrantPermissionExtension extension = GrantPermissionExtension.grant(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE
);
From an initial check, it didn't seem necessary to apply this extension however - the permissions were automatically granted to my emulator regardless of whether I used it or not. Is there some special configuration to disable the automatic granting of permissions that you can provide me with?
Seems in JUnit4, also if the rule GrantPermissionRule is initialized, related permissions will be granted directly.
Any progress on this recently?
No offense, but currently we're facing an android permission handling issue, this blocks a lot of our Java related test suites. However, if I write the test suite in Python, I never have to deal with the annoying permission handling 'cause we can run our test in su. With all these trouble, guess eventually I have to write and run my tests with Python3.
@mannodermaus Any updates on this feature?
I posted an exemplary implementation above and haven't heard any feedback to the contrary that it works. Are you facing any problems with that snippet, or does it work for you and you're mainly asking when it would be available in a released version of the library?
Thank you for your response, @mannodermaus.
It works exceptionally well for me. I'm curious about the possibility of adding this to the library. Managing it ourselves might lead to neglect over time.
Including it in the library would empower the community to maintain and update it as necessary, making it easier for consumers to stay up-to-date.
I believe this is a vital feature to incorporate, given the frequent need for permissions in Android development. Do you think it aligns with the library's scope?
Personally, I believe it does. What's your perspective?
Thanks for confirming that it works for you! I'll see what I can do in regards to pushing this into the next version of the instrumentation core shortly.
This is now available as part of the new android-test-extensions artifact:
dependencies {
androidTestImplementation("de.mannodermaus.junit5:android-test-extensions:1.4.0")
}