Robotium自动化测试框架教程
【免费下载链接】robotium Android UI Testing 项目地址: https://gitcode.com/gh_mirrors/rob/robotium
概述
Robotium是一个强大的Android UI自动化测试框架,支持原生应用和混合应用的测试。它提供了简单易用的API,让开发者能够快速编写稳定可靠的自动化测试用例。Robotium基于Instrumentation框架构建,可以直接与Android测试类如ActivityInstrumentationTestCase2和SingleLaunchActivityTestCase配合使用。
核心优势
- 全面支持:原生应用、混合应用、WebView
- 简单易用:API设计直观,学习成本低
- 自动处理:多Activity切换、对话框、菜单等
- 稳定可靠:运行时绑定UI组件,测试用例更健壮
- 高效执行:测试执行速度快,适合持续集成
环境配置
Maven依赖配置
<dependency>
<groupId>com.jayway.android.robotium</groupId>
<artifactId>robotium-solo</artifactId>
<version>5.6.3</version>
<scope>test</scope>
</dependency>
Gradle配置
dependencies {
androidTestImplementation 'com.jayway.android.robotium:robotium-solo:5.6.3'
}
核心组件架构
基础用法
初始化Robotium
public class LoginActivityTest extends ActivityInstrumentationTestCase2<LoginActivity> {
private Solo solo;
public LoginActivityTest() {
super(LoginActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
}
@Override
protected void tearDown() throws Exception {
solo.finishOpenedActivities();
super.tearDown();
}
}
常用操作示例
1. 点击操作
// 点击文本
solo.clickOnText("登录");
solo.clickOnText("确定", 1); // 点击第二个匹配的"确定"文本
// 点击按钮
solo.clickOnButton("提交");
solo.clickOnButton(0); // 点击第一个按钮
// 点击视图
View loginButton = solo.getView(R.id.btn_login);
solo.clickOnView(loginButton);
// 长按操作
solo.clickLongOnText("删除");
solo.clickLongOnView(deleteButton, 2000); // 长按2秒
2. 文本输入
// 在EditText中输入文本
solo.enterText(0, "test@example.com"); // 在第一个EditText中输入
solo.enterText(solo.getEditText(R.id.et_password), "password123");
// 清空文本
solo.clearEditText(0);
solo.clearEditText(solo.getEditText(R.id.et_username));
// 模拟键盘输入
solo.typeText(0, "slow typing"); // 逐个字符输入
3. 等待和断言
// 等待元素出现
solo.waitForText("欢迎页面", 1, 5000); // 等待5秒
solo.waitForView(R.id.welcome_layout);
solo.waitForView(TextView.class, 2, 3000); // 等待第二个TextView
// 断言当前Activity
solo.assertCurrentActivity("应该在主页面", MainActivity.class);
solo.assertCurrentActivity("应该是登录页面", "LoginActivity");
// 内存断言
solo.assertMemoryNotLow();
4. 滚动操作
// 滚动到列表底部/顶部
solo.scrollToBottom();
solo.scrollToTop();
// 滚动列表到指定行
solo.scrollListToLine(listView, 20); // 滚动到第20行
// 指定方向滚动
solo.scrollToSide(Solo.RIGHT); // 向右滚动
solo.scrollToSide(Solo.LEFT, 0.5f, 10); // 向左滚动50%,10步
高级功能
WebView测试
// 等待Web元素
solo.waitForWebElement(By.id("submit-btn"));
solo.waitForWebElement(By.name("username"), 3, 5000, true);
// 点击Web元素
solo.clickOnWebElement(By.cssSelector(".login-button"));
solo.clickOnWebElement(By.xpath("//button[@type='submit']"), 1, true);
// 在Web元素中输入文本
solo.enterTextInWebElement(By.id("email"), "user@example.com");
solo.typeTextInWebElement(By.name("password"), "secret123", 0);
RecyclerView操作
// 点击RecyclerView中的项目
solo.clickInRecyclerView(3, 0, R.id.item_layout); // 点击第一个RecyclerView的第4个项目
// 等待RecyclerView项目
boolean found = solo.waitForText("Item 5", 1, 3000);
手势操作
// 拖拽操作
solo.drag(100, 300, 200, 400, 10); // 从(100,200)拖拽到(300,400),10步
// 缩放手势
PointF start1 = new PointF(100, 200);
PointF start2 = new PointF(300, 200);
PointF end1 = new PointF(50, 200);
PointF end2 = new PointF(350, 200);
solo.pinchToZoom(start1, start2, end1, end2);
// 旋转手势
PointF center1 = new PointF(200, 300);
PointF center2 = new PointF(200, 400);
solo.rotateLarge(center1, center2);
截图功能
// 单张截图
solo.takeScreenshot(); // 默认名称
solo.takeScreenshot("login_screen"); // 指定名称
solo.takeScreenshot("high_quality", 90); // 指定质量(0-100)
// 连续截图序列
solo.startScreenshotSequence("animation", 80, 100, 50); // 质量80,间隔100ms,最多50帧
// ... 执行动画操作 ...
solo.stopScreenshotSequence();
配置选项
Config类配置
public void setUp() throws Exception {
Solo.Config config = new Solo.Config();
config.timeout_small = 15000; // 小超时15秒
config.timeout_large = 30000; // 大超时30秒
config.sleepDuration = 300; // 睡眠时间300ms
config.sleepMiniDuration = 150; // 最小睡眠时间150ms
config.shouldScroll = true; // 启用自动滚动
config.useJavaScriptToClickWebElements = true; // 使用JS点击Web元素
solo = new Solo(getInstrumentation(), config, getActivity());
}
超时配置
// 全局超时设置
Timeout.setSmallTimeout(8000); // 设置小超时为8秒
Timeout.setLargeTimeout(20000); // 设置大超时为20秒
// 方法级别超时
solo.waitForText("加载完成", 1, 10000); // 等待10秒
solo.waitForView(R.id.content, 1, 15000, true); // 等待15秒
最佳实践
测试用例组织结构
public class ComprehensiveAppTest extends ActivityInstrumentationTestCase2<MainActivity> {
private Solo solo;
public ComprehensiveAppTest() {
super(MainActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
solo = new Solo(getInstrumentation(), getActivity());
}
public void testLoginFlow() {
// 测试登录流程
solo.enterText(0, "testuser");
solo.enterText(1, "password123");
solo.clickOnButton("登录");
solo.waitForActivity(DashboardActivity.class, 5000);
solo.assertCurrentActivity("应该在仪表板", DashboardActivity.class);
}
public void testNavigation() {
// 测试导航功能
solo.clickOnText("设置");
solo.waitForText("系统设置", 1, 3000);
solo.goBack();
solo.waitForActivity(MainActivity.class, 3000);
}
public void testDataValidation() {
// 测试数据验证
solo.enterText(0, "invalid-email");
solo.clickOnButton("提交");
assertTrue("应该显示错误消息", solo.waitForText("邮箱格式错误", 1, 2000));
}
@Override
protected void tearDown() throws Exception {
solo.finishOpenedActivities();
super.tearDown();
}
}
异常处理策略
public void testRobustScenario() {
try {
// 尝试执行可能失败的操作
solo.clickOnText("不存在的按钮");
fail("应该抛出异常");
} catch (Exception e) {
// 优雅地处理异常,继续测试
Log.d("Test", "预期中的异常: " + e.getMessage());
}
// 使用waitFor方法处理异步操作
if (solo.waitForText("加载中", 1, 3000)) {
solo.waitForText("加载完成", 1, 10000);
}
// 检查网络状态
if (!solo.waitForCondition(new Condition() {
@Override
public boolean isSatisfied() {
return isNetworkAvailable();
}
}, 5000)) {
Log.w("Test", "网络不可用,跳过网络相关测试");
return;
}
}
性能优化技巧
public void testPerformance() {
// 调整等待策略
Solo.Config config = new Solo.Config();
config.sleepDuration = 100; // 减少等待时间
config.sleepMiniDuration = 50;
solo = new Solo(getInstrumentation(), config, getActivity());
// 批量操作减少UI交互
solo.enterText(0, "user");
solo.enterText(1, "pass");
solo.clickOnButton("登录");
// 使用更精确的选择器
solo.clickOnView(solo.getView(R.id.specific_button));
instead of
solo.clickOnText("按钮");
}
常见问题解决方案
1. 元素找不到问题
// 解决方案:增加等待时间和滚动
solo.waitForText("目标文本", 1, 10000, true); // 等待10秒,启用滚动
// 使用更精确的定位方式
View specificView = solo.getView(R.id.unique_id, 0);
solo.clickOnView(specificView);
// 检查是否在正确的Activity
solo.assertCurrentActivity("应该在正确的页面", ExpectedActivity.class);
2. WebView测试问题
// 确保WebView已加载完成
solo.waitForWebElement(By.id("web_element"), 1, 15000, true);
// 使用JavaScript点击(如果需要)
Solo.Config config = new Solo.Config();
config.useJavaScriptToClickWebElements = true;
solo = new Solo(getInstrumentation(), config, getActivity());
3. 异步操作处理
// 使用waitForCondition处理复杂异步场景
solo.waitForCondition(new Condition() {
@Override
public boolean isSatisfied() {
return solo.searchButton("下一步") &&
!solo.searchText("加载中");
}
}, 10000);
// 组合等待条件
solo.waitForText("操作完成", 1, 5000);
solo.waitForView(R.id.success_indicator);
调试技巧
日志调试
// 启用Robotium命令日志
Solo.Config config = new Solo.Config();
config.commandLogging = true;
config.commandLoggingTag = "RobotiumTest";
solo = new Solo(getInstrumentation(), config, getActivity());
// 查看当前视图层次
ArrayList<View> views = solo.getViews();
for (View view : views) {
Log.d("ViewDebug", "View: " + view.getClass().getSimpleName() +
", ID: " + (view.getId() == View.NO_ID ? "NO_ID" : view.getResources().getResourceName(view.getId())));
}
可视化调试
// 使用illustrate方法可视化操作
solo.illustrate(new Illustration.Builder()
.addPoint(100, 200, 1.0f)
.addPoint(300, 400, 0.5f)
.build());
// 截图调试
solo.takeScreenshot("debug_step_1");
// 执行操作...
solo.takeScreenshot("debug_step_2");
集成到CI/CD流程
Jenkins配置示例
pipeline {
agent any
stages {
stage('测试') {
steps {
sh './gradlew connectedAndroidTest'
}
post {
always {
junit '**/build/test-results/**/*.xml'
archiveArtifacts '**/build/outputs/androidTest-results/**/*'
}
}
}
}
}
测试报告生成
<!-- 在build.gradle中配置测试报告 -->
android {
testOptions {
【免费下载链接】robotium Android UI Testing 项目地址: https://gitcode.com/gh_mirrors/rob/robotium
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



