得到
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
# UI Testing
|
||||
|
||||
## Setup
|
||||
Add the Compose testing library to your dependencies in build.gradle
|
||||
|
||||
```kotlin
|
||||
androidTestImplementation("androidx.compose.ui:ui-test:$compose_version")
|
||||
debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")
|
||||
```
|
||||
|
||||
## Example
|
||||
Let's say you have the following example code, it's a button with a text that says **Hello** and when you click on it, it turns to **Bye**
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun TestingExample() {
|
||||
val state = remember { mutableStateOf("Hello") }
|
||||
Button(onClick = { state.value = "Bye" }) {
|
||||
Text(state.value)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## TestRule
|
||||
To run this Composable in your test Code you have 2 options:
|
||||
|
||||
### 1) createComposeRule()
|
||||
```kotlin
|
||||
@Rule
|
||||
@JvmField
|
||||
var composeTestRule: ComposeContentTestRule = createComposeRule()
|
||||
```
|
||||
|
||||
You can use this when you want to run your Composable without a specific Activity. You can then use the **setContent()** from the TestRule to host your Composable.
|
||||
|
||||
```kotlin
|
||||
composeTestRule.setContent {
|
||||
TestingExample()
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### 2) createAndroidComposeRule()
|
||||
```kotlin
|
||||
@Rule
|
||||
@JvmField
|
||||
var composeTestRule: ComposeContentTestRule = createAndroidComposeRule<UiTestingDemoActivity>()
|
||||
```
|
||||
|
||||
You can use this when you want to start your test with a specific Activity.
|
||||
|
||||
## Interaction with Composables
|
||||
|
||||
Now we want to test how the Composable reacts when we interact with it.
|
||||
Usually in Tests we would use Espresso for that, but you can use that only for classic Android Views and not for Composables.
|
||||
|
||||
The ComposeTestRule will offer a similar API
|
||||
|
||||
```kotlin
|
||||
class ExampleUiTestWithAndroidComposeRule {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
var composeTestRule: ComposeContentTestRule = createAndroidComposeRule<UiTestingDemoActivity>()
|
||||
|
||||
@Test
|
||||
fun whenIClickOnButton_TheTextShouldChange() {
|
||||
composeTestRule.onNodeWithText("Hello").assertExists()
|
||||
composeTestRule.onNodeWithText("Hello").performClick()
|
||||
composeTestRule.onNodeWithText("Hello").assertDoesNotExist()
|
||||
composeTestRule.onNodeWithText("Bye").assertExists()
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
As you can see above we used the TestRule methods to click on the node with the text **Hello** and asserted that the text changed to **Bye**
|
||||
|
||||
The TestRule offers a lot of different methods. You can find a cheatSheet [here](https://developer.android.com/jetpack/compose/testing-cheatsheet)
|
||||
|
||||
### TestTags
|
||||
The test above is only half correct, because it looks for the text inside the button and not the button itself.
|
||||
Composables have no resource ids so we cant just use **onView(withId(R.id.my_view))** to find a Composable in a test, also we can't find Composables of a specific "type"
|
||||
like a button, because everything is just a Composable function.
|
||||
|
||||
When you can't find a Composable by a text and you want to make it detectable in your test. Jetpack Compose offers the concept of a **TestTag**.
|
||||
testTag is a modifier that needs to be set to a Composable. It expects a string which will be used as a reference in your test.
|
||||
|
||||
```kotlin
|
||||
@Composable
|
||||
fun TestingExample() {
|
||||
val state = remember { mutableStateOf("Hello") }
|
||||
Button(onClick = { state.value = "Bye" }, modifier = Modifier.testTag("MyTestTag")) {
|
||||
Text(state.value)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now you can use **onNodeWithTag("MyTestTag")** to find the button Composable.
|
||||
|
||||
```kotlin
|
||||
@Test
|
||||
fun whenIClickOnButton_TheTextShouldChange() {
|
||||
composeTestRule.onNodeWithTag("MyTestTag").assertTextEquals("Hello")
|
||||
composeTestRule.onNodeWithTag("MyTestTag").performClick()
|
||||
composeTestRule.onNodeWithText("Hello").assertDoesNotExist()
|
||||
composeTestRule.onNodeWithTag("MyTestTag").assertTextEquals("Bye")
|
||||
}
|
||||
```
|
||||
|
||||
### PrintToLog
|
||||
When you want to get more information about how the node tree of a Composable looks like,
|
||||
you can use **printToLog()** on a node.
|
||||
|
||||
```kotlin
|
||||
composeTestRule.onNodeWithTag("MyTestTag").printToLog("XXX")
|
||||
```
|
||||
|
||||
will print to logcat:
|
||||
|
||||
```kotlin
|
||||
2022-01-07 22:58:55.048 9567-9587/de.jensklingenberg.jetpackcomposeplayground D/XXX: printToLog:
|
||||
Printing with useUnmergedTree = 'false'
|
||||
Node #2 at (l=0.0, t=325.0, r=195.0, b=424.0)px, Tag: 'MyTestTag'
|
||||
Role = 'Button'
|
||||
Text = '[Hello]'
|
||||
Actions = [OnClick, GetTextLayoutResult]
|
||||
MergeDescendants = 'true'
|
||||
```
|
||||
|
||||
## See also:
|
||||
* [Full Example Code](https://github.com/Foso/Jetpack-Compose-Playground/blob/master/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithAndroidComposeRule.kt)
|
||||
* [Full Example Code](https://github.com/Foso/Jetpack-Compose-Playground/blob/master/app/src/androidTest/java/de/jensklingenberg/jetpackcomposeplayground/ExampleUiTestWithComposeRule.kt)
|
||||
Reference in New Issue
Block a user