mobile-app-testing

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Mobile App Testing

移动应用测试

Implement comprehensive testing strategies for mobile applications.
为移动应用实施全面的测试策略。

Testing Pyramid

测试金字塔

LevelToolsCoverage
UnitJest, XCTest, JUnit70%
IntegrationDetox, Espresso20%
E2EAppium, Detox10%
层级工具覆盖率
单元测试Jest, XCTest, JUnit70%
集成测试Detox, Espresso20%
端到端测试Appium, Detox10%

React Native (Jest + Detox)

React Native(Jest + Detox)

javascript
// Unit test
describe('CartService', () => {
  it('calculates total correctly', () => {
    const cart = new CartService();
    cart.addItem({ price: 10, quantity: 2 });
    expect(cart.getTotal()).toBe(20);
  });
});

// E2E test (Detox)
describe('Login flow', () => {
  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('should login successfully', async () => {
    await element(by.id('email-input')).typeText('user@example.com');
    await element(by.id('password-input')).typeText('password123');
    await element(by.id('login-button')).tap();
    await expect(element(by.id('dashboard'))).toBeVisible();
  });
});
javascript
// Unit test
describe('CartService', () => {
  it('calculates total correctly', () => {
    const cart = new CartService();
    cart.addItem({ price: 10, quantity: 2 });
    expect(cart.getTotal()).toBe(20);
  });
});

// E2E test (Detox)
describe('Login flow', () => {
  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('should login successfully', async () => {
    await element(by.id('email-input')).typeText('user@example.com');
    await element(by.id('password-input')).typeText('password123');
    await element(by.id('login-button')).tap();
    await expect(element(by.id('dashboard'))).toBeVisible();
  });
});

iOS (XCTest)

iOS(XCTest)

swift
func testLoginSuccess() {
    let app = XCUIApplication()
    app.launch()

    app.textFields["email"].tap()
    app.textFields["email"].typeText("user@example.com")
    app.secureTextFields["password"].typeText("password123")
    app.buttons["Login"].tap()

    XCTAssertTrue(app.staticTexts["Welcome"].exists)
}
swift
func testLoginSuccess() {
    let app = XCUIApplication()
    app.launch()

    app.textFields["email"].tap()
    app.textFields["email"].typeText("user@example.com")
    app.secureTextFields["password"].typeText("password123")
    app.buttons["Login"].tap()

    XCTAssertTrue(app.staticTexts["Welcome"].exists)
}

Android (Espresso)

Android(Espresso)

kotlin
@Test
fun loginSuccess() {
    onView(withId(R.id.email)).perform(typeText("user@example.com"))
    onView(withId(R.id.password)).perform(typeText("password123"))
    onView(withId(R.id.loginButton)).perform(click())
    onView(withId(R.id.dashboard)).check(matches(isDisplayed()))
}
kotlin
@Test
fun loginSuccess() {
    onView(withId(R.id.email)).perform(typeText("user@example.com"))
    onView(withId(R.id.password)).perform(typeText("password123"))
    onView(withId(R.id.loginButton)).perform(click())
    onView(withId(R.id.dashboard)).check(matches(isDisplayed()))
}

Best Practices

最佳实践

  • Test business logic first (unit tests)
  • Mock external dependencies
  • Test both success and failure paths
  • Automate critical user flows
  • Maintain >80% code coverage
  • Test on real devices periodically
  • 优先测试业务逻辑(单元测试)
  • 模拟外部依赖
  • 同时测试成功和失败路径
  • 自动化关键用户流程
  • 保持代码覆盖率>80%
  • 定期在真实设备上测试

Avoid

需避免的情况

  • Testing implementation details
  • Hardcoded test data
  • Interdependent tests
  • Skipping error case testing
  • 测试实现细节
  • 硬编码测试数据
  • 相互依赖的测试用例
  • 跳过错误场景测试