关于 espresso-skill
espresso-skill 是面向 QA 工程师和 Android 开发者的 Espresso Android UI 测试参考技能,提供 Kotlin 测试模式,涵盖视图查找、交互和断言,以及本地和 TestMu AI 云端执行指南。
主要功能
- 01Kotlin Espresso 测试模式
- 02视图匹配器、操作与断言
- 03用于异步 UI 的 Idling Resources
- 04Intent 与 RecyclerView 测试
- 05本地和云端执行指南
适用场景
- 01测试 Android 登录界面和控件
- 02检查异步操作期间的 UI 行为
- 03验证 Intent 和 RecyclerView 交互
- 04在本地设备或云端运行仪器测试
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ lambdatest/ agent-skills --skill espresso-skill安装后在 Claude Code 中输入/espresso-skill确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
reference/advanced-patterns.mdcloud-integration.mdplaybook.md详细介绍
Espresso 自动化技能
你是一名专精于 Espresso UI 测试的资深 Android QA 工程师。
步骤 1 — 执行目标
├─ Mentions "cloud", "TestMu", "LambdaTest", "device farm"?
│ └─ TestMu AI cloud (upload APK + test APK)
│
├─ Mentions "emulator", "local", "connected device"?
│ └─ Local: ./gradlew connectedAndroidTest
│
└─ Default → Local emulator
核心模式 — Kotlin(默认)
基础测试
@RunWith(AndroidJUnit4::class)
class LoginTest {
@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)
@Test
fun loginWithValidCredentials() {
// Type email
onView(withId(R.id.emailInput))
.perform(typeText("[email protected]"), closeSoftKeyboard())
// Type password
onView(withId(R.id.passwordInput))
.perform(typeText("password123"), closeSoftKeyboard())
// Click login button
onView(withId(R.id.loginButton))
.perform(click())
// Verify dashboard is displayed
onView(withId(R.id.dashboardTitle))
.check(matches(isDisplayed()))
.check(matches(withText("Welcome")))
}
@Test
fun loginWithInvalidCredentials_showsError() {
onView(withId(R.id.emailInput))
.perform(typeText("[email protected]"), closeSoftKeyboard())
onView(withId(R.id.passwordInput))
.perform(typeText("wrong"), closeSoftKeyboard())
onView(withId(R.id.loginButton))
.perform(click())
onView(withId(R.id.errorText))
.check(matches(isDisplayed()))
.check(matches(withText(containsString("Invalid"))))
}
}
ViewMatchers(查找元素)
// By ID (best)
onView(withId(R.id.loginButton))
// By text
onView(withText("Login"))
// By content description (accessibility)
onView(withContentDescription("Submit form"))
// By hint text
onView(withHint("Enter your email"))
// Combined matchers
onView(allOf(withId(R.id.button), withText("Submit"), isDisplayed()))
// In RecyclerView
onView(withId(R.id.recyclerView))
.perform(RecyclerViewActions.actionOnItemAtPosition<ViewHolder>(0, click()))
// By parent
onView(allOf(withText("Delete"), isDescendantOfA(withId(R.id.toolbar))))
ViewActions(执行操作)
.perform(click()) // Tap
.perform(longClick()) // Long press
.perform(typeText("hello")) // Type text
.perform(replaceText("new text")) // Replace text
.perform(clearText()) // Clear field
.perform(closeSoftKeyboard()) // Dismiss keyboard
.perform(scrollTo()) // Scroll to element
.perform(swipeUp()) // Swipe gesture
.perform(swipeDown())
.perform(swipeLeft())
.perform(swipeRight())
.perform(pressBack()) // Back button
ViewAssertions(检查状态)
.check(matches(isDisplayed())) // Visible
.check(matches(not(isDisplayed()))) // Not visible
.check(matches(withText("Expected"))) // Text matches
.check(matches(isEnabled())) // Enabled
.check(matches(isChecked())) // Checkbox checked
.check(matches(hasErrorText("Required"))) // Error text
.check(doesNotExist()) // Not in hierarchy
Idling Resources(异步操作)
// Register before test
@Before
fun setUp() {
IdlingRegistry.getInstance().register(myIdlingResource)
}
// Unregister after test
@After
fun tearDown() {
IdlingRegistry.getInstance().unregister(myIdlingResource)
}
// Custom IdlingResource for network calls
class NetworkIdlingResource : IdlingResource {
private var callback: IdlingResource.ResourceCallback? = null
private var isIdle = true
override fun getName() = "NetworkIdlingResource"
override fun isIdleNow() = isIdle
override fun registerIdleTransitionCallback(callback: ResourceCallback) {
this.callback = callback
}
fun setIdle(idle: Boolean) {
isIdle = idle
if (idle) callback?.onTransitionToIdle()
}
}
反模式
| 不推荐 | 推荐 | 原因 |
|---|---|---|
Thread.sleep() | IdlingResources | Espresso 会自动同步 UI 线程 |
| 类 XPath 遍历 | withId(R.id.x) | 直接使用 ID 速度最快 |
| 跨 Activity 测试 | 测试单个屏幕,模拟数据 | 隔离 |
不调用 closeSoftKeyboard() | 每次 typeText() 后都关闭键盘 | 键盘会遮挡元素 |
TestMu AI Cloud
# 1. Build APK and test APK
./gradlew assembleDebug assembleDebugAndroidTest
# 2. Upload both to LambdaTest
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "appFile=@app/build/outputs/apk/debug/app-debug.apk" \
-F "type=android"
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "appFile=@app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk" \
-F "type=android"
# 3. Execute on real devices via API
curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://mobile-api.lambdatest.com/framework/v1/espresso/build" \
-H "Content-Type: application/json" \
-d '{
"app": "lt://APP123",
"testSuite": "lt://TEST456",
"device": ["Pixel 8-14", "Galaxy S24-14"],
"build": "Espresso Cloud Build",
"video": true, "deviceLog": true
}'
build.gradle 设置
android {
defaultConfig {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
}
快速参考
| 任务 | 命令/代码 |
|---|---|
| 运行所有测试 | ./gradlew connectedAndroidTest |
| 运行指定类 | ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.LoginTest |
| 在指定设备上运行 | ./gradlew connectedAndroidTest -PtestDevice=emulator-5554 |
| Intent 验证 | Intents.init() → intended(hasComponent(...)) → Intents.release() |
| 滚动 RecyclerView | RecyclerViewActions.scrollToPosition<>(10) |
| 截图 | Screenshot.capture(activityRule.activity) |
参考文件
| 文件 | 何时阅读 |
|---|---|
reference/cloud-integration.md | LambdaTest Espresso、设备云、API |
reference/advanced-patterns.md | Intents、RecyclerView、自定义匹配器 |
深入模式 → reference/playbook.md
| § | 章节 | 行数 |
|---|---|---|
| 1 | 项目设置 | Gradle 依赖、Orchestrator |
| 2 | 测试结构与生命周期 | 规则、权限、注解 |
| 3 | 自定义匹配器与 ViewActions | RecyclerView、等待、滚动 |
| 4 | RecyclerView 测试 | 滚动、点击子项、滑动、断言 |
| 5 | Idling Resources | 计数、OkHttp、自定义 |
| 6 | Intent 测试 | 分享、桩、相机 |
| 7 | 使用 MockWebServer 进行 API 测试 | 入队、错误处理 |
| 8 | CI/CD 集成 | GitHub Actions、模拟器运行器 |
| 9 | 调试速查 | 10 个常见问题 |
| 10 | 最佳实践检查清单 | 13 项 |
评论
支持 Markdown