🪒

Jetpack Compose UI Test

2024/01/26に公開

読んでほしい人

  • Jetpack Compose UI Testに興味がある.
  • 簡単なテストで良いので書いてみたい。

補足情報

テストに必要なパッケージは最初から入ってます。

こちらの動画を参考にUI Testの練習をしていきましょう!
https://www.youtube.com/watch?v=kxOwAIdTT9A

記事の内容

UI Testをするファイルを動画で解説しているディレクトリに作成してください。こちらにテストコードを書いていきます。

Hello WorldするUI作りましょう

実行するアプリのコード
package com.junichi.composetest

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.junichi.composetest.ui.theme.ComposeTestTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTestTheme {
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                    Text(text = "Hello World!")
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeTestTheme {
    }
}

UI Testのコードを書く。Hello World!というテキストがあればテストが通る!

UI Testのコード
package com.junichi.composetest

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithText
import org.junit.Rule
import org.junit.Test

class ComposeUITest {

    @get:Rule
    val composeRule = createAndroidComposeRule<MainActivity>()


    @Test
    fun testIfHelloWorldIsDisplayed() {
        // Hello Worldというテキストが表示されているかどうかを確認する
        composeRule.onNodeWithText("Hello World!").assertIsDisplayed()
    }
}

tagを追加してみる。もしtagのテキストが違ったらエラーが出る!

tagを追加したUI
package com.junichi.composetest

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.junichi.composetest.ui.theme.ComposeTestTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTestTheme {
                Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
                    Text(text = "Hello World!", modifier = Modifier.testTag("helloText").semantics {
                        contentDescription = "Hello world button"
                    })
                }
            }
        }
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeTestTheme {
    }
}
tagがあるかテストする
package com.junichi.composetest

import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import org.junit.Rule
import org.junit.Test

class ComposeUITest {

    @get:Rule
    val composeRule = createAndroidComposeRule<MainActivity>()


    @Test
    fun testIfHelloWorldIsDisplayed() {
        // hello world buttonというcontentDescriptionがついたノードが表示されているかどうかを確認する
        composeRule.onNodeWithContentDescription("Hello world button").assertIsDisplayed()
    }
}



カウンターのテストをする

ボタンを押すと、カウントがされるUIを作成します。これをUI Testのファイルでimportしてカウントがされたかテストします。

カウンターのUI
package com.junichi.composetest

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.tooling.preview.Preview
import com.junichi.composetest.ui.theme.ComposeTestTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeTestTheme {
                Counter()
                }
            }
        }
    }

@Composable
fun Counter() {
    var counter by remember { mutableStateOf(0) }

    Column (modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.Center, horizontalAlignment = Alignment.CenterHorizontally) {
        Button(onClick = { counter++ }, modifier = Modifier.testTag("incrementButton")) {
          Text(text = "Increment")
        }

        Text(text = "The current count is $counter", Modifier.testTag("text"))
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    ComposeTestTheme {
    }
}

3回ボタンをカウントして期待する値が3だったらテストが通るテストコードです。

カウンターのテストコード
package com.junichi.composetest

import androidx.compose.ui.test.assert
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import org.junit.Rule
import org.junit.Test

class ComposeUITest {

    @get:Rule
    // createComposeRuleに修正してください
    val composeRule = createComposeRule()


    @Test
    fun testIfCounterIsFine() {
        // setContentを呼び出す
        composeRule.setContent {
            // CounterのComposableを呼び出す
            Counter()
        }
        // カウンターは最初は0なので、0であることを確認。0でなければテストは失敗します。
        composeRule.onNodeWithTag("text").assert(hasText("The current count is 0"))
        // カウンターを3回インクリメントさせるので、composeRule.onNodeWithTagを3回呼び出す
        composeRule.onNodeWithTag("incrementButton").performClick()
        composeRule.onNodeWithTag("incrementButton").performClick()
        composeRule.onNodeWithTag("incrementButton").performClick()
        // カウンターは3になるので、3であることを確認。3でなければテストは失敗します。
        composeRule.onNodeWithTag("text").assert(hasText("The current count is 3"))
    }
}

期待する値が3ではなければ失敗する!

期待する値が3であればテストが通る!

最後に

今回は、Jetpack ComposeでUI Testをやってみました。知識がないものでしたから最初は分からなかったですね。最近テストコードを書くのを意識してるので書いていきたいですね。

公式でも紹介はされている:
https://developer.android.com/jetpack/compose/testing?hl=ja

Discussion