Files
ai-proj-helper/skills-dev/dev-test-plugin/skills/dev-test/android-testing.md
John Qiu 712063071c refactor: 通用技能按类别拆分为独立目录
skills/ → skills-dev(9), skills-req(10), skills-ops(4),
skills-integration(8), skills-biz(4), skills-workflow(7)

generate-marketplace.py 改为自动扫描所有 skills-* 目录。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:31:58 +10:30

146 lines
3.0 KiB
Markdown

# Android 测试 (JUnit + Espresso)
## 运行测试
```bash
# 单元测试
./gradlew test
# UI 测试
./gradlew connectedAndroidTest
```
## 单元测试 (JUnit)
```kotlin
class TaskViewModelTest {
@get:Rule
val instantTaskRule = InstantTaskExecutorRule()
@get:Rule
val coroutineRule = MainCoroutineRule()
private lateinit var viewModel: TaskViewModel
private lateinit var repository: FakeTaskRepository
@Before
fun setup() {
repository = FakeTaskRepository()
viewModel = TaskViewModel(repository)
}
@Test
fun `fetchTasks updates state`() = runTest {
// Arrange
repository.addTasks(listOf(
Task(1, "Task 1"),
Task(2, "Task 2")
))
// Act
viewModel.fetchTasks()
// Assert
val tasks = viewModel.tasks.first()
assertEquals(2, tasks.size)
}
@Test
fun `createTask adds task`() = runTest {
// Act
viewModel.createTask("New Task")
// Assert
val tasks = viewModel.tasks.first()
assertTrue(tasks.any { it.title == "New Task" })
}
}
```
## UI 测试 (Espresso)
```kotlin
@RunWith(AndroidJUnit4::class)
@LargeTest
class TaskListActivityTest {
@get:Rule
val activityRule = ActivityScenarioRule(TaskListActivity::class.java)
@Test
fun displayTaskList() {
onView(withId(R.id.taskList))
.check(matches(isDisplayed()))
}
@Test
fun clickTask_opensDetail() {
onView(withId(R.id.taskList))
.perform(RecyclerViewActions.actionOnItemAtPosition<TaskViewHolder>(0, click()))
onView(withId(R.id.taskDetail))
.check(matches(isDisplayed()))
}
@Test
fun addTask_showsInList() {
// Click add button
onView(withId(R.id.addButton)).perform(click())
// Enter title
onView(withId(R.id.titleInput))
.perform(typeText("New Task"), closeSoftKeyboard())
// Save
onView(withId(R.id.saveButton)).perform(click())
// Verify in list
onView(withText("New Task"))
.check(matches(isDisplayed()))
}
}
```
## Compose UI 测试
```kotlin
@RunWith(AndroidJUnit4::class)
class TaskListScreenTest {
@get:Rule
val composeRule = createComposeRule()
@Test
fun taskList_displays() {
val tasks = listOf(
Task(1, "Task 1"),
Task(2, "Task 2")
)
composeRule.setContent {
TaskListScreen(tasks = tasks)
}
composeRule.onNodeWithText("Task 1").assertExists()
composeRule.onNodeWithText("Task 2").assertExists()
}
@Test
fun taskClick_callsOnClick() {
var clickedId: Int? = null
val tasks = listOf(Task(1, "Task 1"))
composeRule.setContent {
TaskListScreen(
tasks = tasks,
onTaskClick = { clickedId = it.id }
)
}
composeRule.onNodeWithText("Task 1").performClick()
assertEquals(1, clickedId)
}
}
```