mcpField
E
espresso-skill

espresso-skill

github.com/lambdatest测试与质量384226 次安装2 周前更新
代码仓库

关于 espresso-skill

espresso-skill 是面向 QA 工程师和 Android 开发者的 Espresso Android UI 测试参考技能,提供 Kotlin 测试模式,涵盖视图查找、交互和断言,以及本地和 TestMu AI 云端执行指南。

主要功能

  1. 01Kotlin Espresso 测试模式
  2. 02视图匹配器、操作与断言
  3. 03用于异步 UI 的 Idling Resources
  4. 04Intent 与 RecyclerView 测试
  5. 05本地和云端执行指南

适用场景

  1. 01测试 Android 登录界面和控件
  2. 02检查异步操作期间的 UI 行为
  3. 03验证 Intent 和 RecyclerView 交互
  4. 04在本地设备或云端运行仪器测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/lambdatest/agent-skills --skill espresso-skill

安装后在 Claude Code 中输入/espresso-skill确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

reference/
advanced-patterns.md
cloud-integration.md
playbook.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()IdlingResourcesEspresso 会自动同步 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()
滚动 RecyclerViewRecyclerViewActions.scrollToPosition<>(10)
截图Screenshot.capture(activityRule.activity)

参考文件

文件何时阅读
reference/cloud-integration.mdLambdaTest Espresso、设备云、API
reference/advanced-patterns.mdIntents、RecyclerView、自定义匹配器

深入模式 → reference/playbook.md

§章节行数
1项目设置Gradle 依赖、Orchestrator
2测试结构与生命周期规则、权限、注解
3自定义匹配器与 ViewActionsRecyclerView、等待、滚动
4RecyclerView 测试滚动、点击子项、滑动、断言
5Idling Resources计数、OkHttp、自定义
6Intent 测试分享、桩、相机
7使用 MockWebServer 进行 API 测试入队、错误处理
8CI/CD 集成GitHub Actions、模拟器运行器
9调试速查10 个常见问题
10最佳实践检查清单13 项

评论

支持 Markdown