Some time ago Android team finally introduced GrantPermissionRule. How does it work with KotlinTest? It doesn’t, but it’s not a big deal.

Some time ago I was doing a bunch of AndroidInstrumented testing and I was so surprised that you couldn’t simply grant your app all permissions! This seems like so obvious issue. And FINALLY Android team provided: GrantPermissionRule.

If usual AndroidInstrumented tests it looks like that:

@Rule @JvmField
val grantPermissionRule: GrantPermissionRule =
            GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION)

Nothing fancy, just a regular @Rule that will automatically grant all listed permissions. I was so relieved to see that!

Then I tried to add in some tests of mine written in KotlinTest and… it doesn’t work. As explained here KotlinTest doesn’t support JUnit rules. And I get the explanation - JUnit5, which is ultimately the future discourages to use @Rules but still - I assume that big user base of KotlinTest uses it on Android, so that’s sad omission.

With no rules, you have two options: implement your own TestListener (KotlinTest way) or just look inside GrantPermissionRule and see what it really does. Fortunately, it doesn’t do much.

Pure Kotlin code, no framework

Quick look under the hood of GrantPermissionRule and fortunately, it’s not complicated. Extracting the important stuff enables us to write this simple method:

private fun grantPermissions(vararg permissions: String) {
        PermissionRequester().apply {
            addPermissions(*permissions)
            requestPermissions()
        }
    }

And you use it like that:

grantPermissions(Manifest.permission.READ_PHONE_STATE)

Very simple!

TestListener for KotlinTest

class PermissionsGranted(vararg val permissions: String) : TestListener {

    override fun beforeTest(description: Description): Unit {
          PermissionRequester().apply {
              addPermissions(*permissions)
              requestPermissions()
          }
    }
}

and usage:

class AwesomeTest : StringSpec() {

  override fun listeners(): List<TestListener> = listOf(PermissionsGranted(Manifest.permission.READ_PHONE_STATE))

  init {
        "system does cool things" { ... }
    }
}

In my opinion for such simple case just a regular method should be enough, but as always - pick what works best for you!