Skip to content

UiTesting ‐ Testing a individual composable

Devrath edited this page Oct 27, 2023 · 1 revision

Dependency Needed

debugImplementation("androidx.compose.ui:ui-test-manifest:1.4.3")
  • This will let us use a createComposeRule in our androidTest.
  • This will not launch our default launcher activity but instead will launch our custom test activity and put the composable in that to test.
  • Thus we can test a composable in isolation
  • So this can be testing unit test for instrumentation.
  • The debugImplementation above registers the test activity in the manifest to be tested.

Important notes

  • Keeping a preview profile state in the composable is useful because we can pass during the testing

Code

ProcuctionCode

Profile.kt

data class Post(
    val id: String,
    val userId: String,
    val title: String,
    val body: String
)

ProfileScreen.kt

@Composable
fun ProfileScreen(
state: ProfileState
) {
    if(state.isLoading) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            CircularProgressIndicator()
        }
    } else {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            state.profile?.user?.let { user ->
                Text(
                    text = user.username,
                    fontSize = 24.sp
                )
            }
            Spacer(modifier = Modifier.height(32.dp))
            Text(text = "Posts:")
            Spacer(modifier = Modifier.height(8.dp))
            LazyColumn(
                modifier = Modifier.fillMaxSize()
            ) {
                items(state.profile?.posts ?: emptyList()) { post ->
                    PostUi(
                        post = post,
                        modifier = Modifier.fillMaxWidth()
                    )
                }
            }
        }
    }
}

@Composable
private fun PostUi(
    post: Post,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .shadow(4.dp)
            .padding(16.dp)
    ) {
        Text(
            text = post.title,
            fontSize = 18.sp
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(text = post.body)
    }
}

fun previewProfileState() = ProfileState(
    profile = Profile(
        user = User(
            id = "test-user",
            username = "Test username"
        ),
        posts = (1..10).map {
            Post(
                id = it.toString(),
                userId = "test-user",
                title = "Title$it",
                body = "Body$it"
            )
        }
    ),
    isLoading = false
)

@Preview(showBackground = true)
@Composable
fun ProfileScreenPreview() {
    MaterialTheme {
        ProfileScreen(
            state = previewProfileState()
        )
    }
}

Test Case

ProfileScreenKtTest.kt

class ProfileScreenKtTest {

    @get:Rule
    val composeRule = createComposeRule()

    @Test
    fun testProfileScreen_whetherUiIsLoaded(){

        // <--------- Set the content with states --------------->
        composeRule.setContent {
            MaterialTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    ProfileScreen(state = previewProfileState())
                }
            }
        }

        // <--------- Perform the assertions for the UI --------->
        // First find the composable in the UI-tree
        composeRule.onNodeWithText("Test username")
            // perform assertion
            .assertIsDisplayed()
    }

}