Composeのテストを試す

- この記事はand factory.inc Advent Calendar 2022 24日目の記事です。
昨日は @ykkd さんの 「[OperationQueueを活用して、前処理,後処理,キャンセル処理が必要なタスクをバックグラウンドで行う](https://qiita.com/ykkd/items/f1cb5807f8c5733fd37e)」でした。

### はじめに
- モチベーションはUIのリグレッションテストの自動化です :shield: 

### 依存の追加

```
androidTestImplementation("androidx.compose.ui:ui-test-junit4:$compose_version")  
```

今回は、"androidx.compose.ui:ui-test-manifest:$compose_version" は使わないので追加していません。
こちらはアクティビティにアクセスする場合に使うようです。( [JetChat](https://github.com/android/compose-samples/blob/main/Jetchat/app/src/androidTest/java/com/example/compose/jetchat/ConversationTest.kt#L49)で使われていたので参考になればと思います。）

### テスト対象のCompose
- テキストを１行または、複数行で表示するUIです

![record-221220131918.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36517/fa95642b-df70-033e-b81a-070dbea69d96.gif)


### UIの仕様について
 - 表示するデータがない場合は表示しない
 - 表示データが１件の場合
   - １件だけ表示。開閉ボタンは表示しない
 - 表示データが複数件の場合
   - 表示直後は１件だけ表示。開閉ボタンを表示する
   - 開閉ボタンをタップすると複数行を表示する

### テストコード

- 表示するデータがない場合は表示しない

``` NoticeTest.kt
@Test
fun `NoticeTest_表示するデータがない場合は非表示`() {
    composeTestRule.setContent {
        NoticeContent(
            notices = listOf(),
            expanded = false,
            onClick = { },
        )
    }
    composeTestRule.onRoot().onChild().assertDoesNotExist()
}
```

 - 表示データが１件の場合
   - １件だけ表示。開閉ボタンは表示しない

``` NoticeTest.kt
@Test
fun `NoticeTest_表示データが１件の場合_１件だけ表示、開閉ボタンは表示しない`() {
    val notice = "notice"
    composeTestRule.setContent {
        NoticeContent(
            notices = listOf(
                Notice(
                    text = notice,
                    noticeColor = "#FFFFFF",
                    noticeThickness = 0
                )
            ),
            expanded = false,
            onClick = { },
        )
    }

    composeTestRule.onAllNodesWithText(notice).assertCountEquals(1)
    composeTestRule.onNode(hasClickAction()).assertDoesNotExist()
}
```

 - 表示データが複数件の場合
   - 表示直後は１件だけ表示。開閉ボタンを表示する

``` NoticeTest.kt
@Test
fun `NoticeTest_表示データが複数件の場合_表示直後は１件だけ表示。開閉ボタンを表示する`() {
    val notice = "notice"

    composeTestRule.setContent {
        NoticeContent(
            notices = listOf(
                Notice(
                    text = notice,
                    noticeColor = "#FFFFFF",
                    noticeThickness = 0
                ),
                Notice(
                    text = notice,
                    noticeColor = "#FFFFFF",
                    noticeThickness = 0
                )
            ),
            expanded = false,
            onClick = { },
        )
    }

    composeTestRule.onAllNodesWithText(notice).assertCountEquals(1)
    composeTestRule.onNodeWithContentDescription("Arrow").assertIsDisplayed()
}
```
 - 表示データが複数件の場合
   - 開閉ボタンをタップすると複数行を表示する

``` NoticeTest.kt
@Test
fun `NoticeTest_表示データが複数件の場合_開閉ボタンをタップすると複数行を表示する`() {
    val notice = "notice"
    val expanded = mutableStateOf(false)

    composeTestRule.setContent {
        NoticeContent(
            notices = listOf(
                Notice(
                    text = notice,
                    noticeColor = "#FFFFFF",
                    noticeThickness = 0
                ),
                Notice(
                    text = notice,
                    noticeColor = "#FFFFFF",
                    noticeThickness = 0
                )
            ),
            expanded = expanded.value,
            onClick = { expanded.value = expanded.value.not() },
        )
    }

    composeTestRule.onAllNodesWithText(notice).assertCountEquals(1)
    composeTestRule.onNode(hasClickAction()).performClick()
    composeTestRule.onAllNodesWithText(notice).assertCountEquals(2)
}
```


### おわりに
- Composeのテストを書いてみましたが、比較的短いコードでUIをテストできるの良いなと感じました
- 実は「開閉ボタンをタップすると複数行を表示する」のテストで複数件を表示した際の開閉ボタンの画像が変わるのですが、ここのテストをうまくかけなかったです。。。良い書き方をご存知の方はコメント頂けると嬉しいです。

- 明日のAdvent Calendarの記事もお楽しみに:santa:

### 参照
https://developer.android.com/jetpack/compose/testing?hl=ja