Search code examples
androidunit-testingjunit4android-jetpack-compose

Jetpack Compose - UI Test with Function Argument


@Composable
fun MyComposable(submit: (String) -> Unit) {
   MyButton(title = "Submit") {
        submit("Hello World!")
   }
}

@Composable
fun MyButton(title: String, submit: (String) -> Unit) {
    Button(onClick = submit) {
        Text(text = title)
    }
}

How can I unit test that submit were to be called?

While in the test I can set the submit result inside MyComposable, it never actually gets called when the test is being ran.

The test would look like this:

    @Test
    fun trySubmit_expectPrint() {
        composeRule.setContent { GetDefaultScreen() }

        //Too lazy to write the hasTestTag, but assume it gets the correct node.
        composeRule.onNodeWithTag("MyComposable").performClick()

        //Assertions here...
    }

    @Composable
    private fun GetDefaultScreen() =
        MyComposable() {
            Log.d("TEST", "Submitting")
        }

My end goal here is to have the scope of that composable in the test change a variable, in order to allow me to verify that that block was ran.

This is all under the assumption that we are still unable to Mock or Spy on final classes with an androidTest (UI test).

If that assumption is wrong, please correct me if there's a method in which I can do that.


Solution

  • I've since come to found something that works for me.

    In the test function, just adding a value that should get changed by the callback, and then making an assertion on that value:

    @Test
    fun myTest() {
        var testValue = ""
        composeTestRule.setContent {
            Button() { testValue = "Hello, World!" }
        }
    
        assertThat(testValue).equals("Hello, World!")
    }