深入探索 Android:硬件访问与应用测试全攻略
1. 深入了解 Android 底层硬件访问
Android 开发者能够以前所未有的方式访问设备的底层硬件。除了摄像头和 LBS 服务等硬件外,Android SDK 还提供了各种 API,用于访问手机的底层硬件功能,具体如下:
- 读取原始传感器数据(如磁力和方向传感器)
- 访问 Wi-Fi 和蓝牙传感器
- 监控电池使用情况和电源管理
需要注意的是,并非所有传感器和硬件在每个 Android 设备上都可用,许多功能属于可选硬件。在尝试使用这些设备功能之前,务必通过编程方式进行测试。不同设备上可用的传感器在可用性和灵敏度方面也存在差异,有些传感器提供原始数据,而有些则依靠服务或软件为应用提供有用的数据。
1.1 读取原始传感器数据
Android SDK 支持的部分设备传感器如下:
| 传感器类型 | 功能 |
| — | — |
| 加速度计 | 测量三维加速度 |
| 光线传感器 | 测量亮度(对相机闪光灯有用) |
| 磁场传感器 | 测量三维磁场 |
| 方向传感器 | 测量设备的方向 |
| 温度传感器 | 测量温度 |
| 接近传感器 | 测量设备到空间中某一点的距离 |
Android 模拟器本身不模拟任何设备传感器,但 OpenIntents 提供了一个便捷的传感器模拟器(http://goo.gl/Ousse),可模拟加速度计、指南针、方向传感器和温度传感器,并将数据传输到模拟器。当然,也可以在目标设备上测试传感器功能。要收集设备传感器的数据,可使用 SensorManager 对象,通过 getSystemService() 方法获取其实例。
1.2 处理 Wi-Fi
具有适当权限(ACCESS_WIFI_STATE 和 CHANGE_WIFI_STATE)的应用程序可以使用 WifiManager 对象访问设备内置的 Wi-Fi 传感器,同样通过 getSystemService() 方法获取其实例。Android SDK 提供了一组 API,用于检索设备可用的 Wi-Fi 网络信息以及 Wi-Fi 网络连接详细信息,这些信息可用于跟踪信号强度、查找接入点或在连接到特定接入点时执行操作。不过,模拟器不模拟 Wi-Fi 支持,因此需要在设备上对 Wi-Fi API 进行所有测试。
1.3 处理蓝牙
Android SDK 在 android.bluetooth 包中包含了蓝牙支持类,可用于扫描支持蓝牙的设备、配对以及处理数据传输。
1.4 管理电源设置和电池寿命
大多数移动设备主要依靠电池供电。若要监控电池,应用程序必须具备 BATTERY_STATS 权限,注册接收 Intent.ACTION_BATTERY_CHANGED 广播意图,并实现 BroadcastReceiver 以提取电池信息并采取所需操作。可监控的电池和电源设置包括:
- 是否存在电池
- 电池健康状况、状态(充电状态)、电压和温度
- 电池充电百分比及相关图标
- 设备是否通过交流或 USB 电源充电
应用程序可利用设备电源状态信息来管理自身的功耗。例如,一个经常消耗大量处理能力的应用程序,在电池电量不足时可禁用一些耗电功能。
2. 测试 Android 应用程序
每个移动开发者都渴望开发出“杀手级应用”,但仅有好的想法是不够的,在发布应用之前进行全面测试至关重要。
2.1 测试最佳实践
移动用户对现代移动应用有诸多期望,包括稳定性、响应性和安全性。稳定性意味着应用程序能正常运行,不会崩溃或损坏用户设备;响应性要求设备始终能对按钮按下和点击事件做出响应,长时间操作应使用进度条或其他活动指示器;安全性则表示应用程序不会有意或无意地滥用用户信任。用户还期望应用程序拥有简洁的用户界面,并且能全天候运行(特别是对于有服务器端的网络应用程序)。
为提高开发过程的质量,可采取以下措施:
- 制定编码标准和指南
- 进行定期版本化构建
- 使用缺陷跟踪系统并建立解决缺陷的流程
- 依据测试计划进行系统的应用程序测试
也可以将应用程序测试外包给第三方,但外包项目的成功很大程度上取决于提供给外包机构的文档质量,如功能规格说明和用例等。
2.2 制定编码标准
当开发者遵循一套预先确定的准则时,他们的代码会更具凝聚力,更易于阅读和维护。开发者应做到以下几点:
- 讨论并确定一种通用的方式来实现错误和异常处理
- 将冗长或处理密集型操作从主 UI 线程移开
- 释放未被积极使用的对象和资源
- 谨慎管理内存并追踪内存泄漏
- 合理使用项目资源,避免在代码或布局文件中硬编码数据和字符串
2.3 进行定期版本化构建
实现可重现的构建过程对于成功的 Android 项目至关重要,特别是对于支持多个 Android SDK 版本、设备或语言的应用程序。要进行定期的版本化构建,可按以下步骤操作:
- 使用源代码控制系统跟踪项目文件
- 定期对项目文件进行版本控制,并进行常规的、可重现的构建
- 通过测试验证每个构建是否按预期执行
许多流行的源代码控制系统,如 Perforce、Subversion、Git 和 CVS,都能很好地与 Eclipse 配合使用,有些还可通过插件实现与 Eclipse 的集成。由于移动项目进展迅速,迭代开发过程通常是移动开发最成功的策略,快速原型设计为开发者和质量保证人员提供了在应用程序到达用户手中之前进行评估的充足机会。
2.4 使用缺陷跟踪系统
缺陷跟踪系统可用于组织和跟踪应用程序的错误或缺陷,并通常与解决这些问题的流程一起使用。解决缺陷一般意味着修复问题,并在后续构建中验证修复是否正确。移动应用程序的缺陷形式多样,有些在所有设备上都会出现,而有些仅在特定设备上出现。除了功能缺陷(即应用程序的某些功能无法正常工作)外,还需测试应用程序在性能、响应性、可用性和状态管理等方面与 Android 操作系统的整体兼容性。
2.5 制定良好的测试计划
测试人员主要依据应用程序的功能规格说明和用户界面文档,来确定应用程序的功能和特性是否得到正确实现。应用程序的功能和工作流程必须在屏幕级别进行详细记录,并通过测试进行验证。在功能规格说明、开发者的实现和测试人员的实际体验之间,可能会存在解释上的差异,这些差异必须作为缺陷解决过程的一部分加以解决。
Android 应用程序测试人员可使用多种工具,尽管手动测试必不可少,但现在也有很多机会将自动化测试纳入测试计划。测试计划需要涵盖以下多个方面:
graph LR
A[测试类型] --> B[功能测试]
A --> C[集成测试]
A --> D[客户端/服务器测试]
A --> E[升级测试]
A --> F[国际化测试]
A --> G[可用性测试]
A --> H[性能测试]
A --> I[一致性测试]
A --> J[边缘情况测试]
- 功能测试 :确保应用程序的功能和特性按照功能规格说明正确运行。
- 集成测试 :确保软件与其他核心设备功能良好集成,例如应用程序应能正确暂停和恢复,并能优雅地处理来自操作系统的中断(如来电、短信、关机等)。
- 客户端/服务器测试 :对于网络移动应用程序,除了测试移动客户端外,还需验证服务器端的功能。
- 升级测试 :Android 设备经常接收固件更新,可能需要对应用程序进行升级。应尽可能对客户端和服务器进行应用程序升级测试,以确保用户的升级过程顺利。
- 国际化测试 :在开发过程早期确保应用程序支持国际化,特别是语言支持。如果应用程序支持多种语言,可能会出现屏幕空间、字符串操作以及货币、日期和时间格式等方面的问题。
- 可用性测试 :从用户界面的角度识别应用程序中缺乏视觉吸引力、难以导航或使用的区域,验证应用程序的资源消耗模型是否符合目标受众的需求。例如,游戏玩家可能会接受图形密集型游戏较短的电池续航时间,但生产力应用程序不应不必要地消耗电池电量。
- 性能测试 :使用 Android SDK 的调试工具监控内存和资源使用情况,识别性能瓶颈、危险的内存泄漏并进行修复。
- 一致性测试 :审查应用程序必须遵守的任何政策、许可协议、条款和法律(包括出口法律),并验证应用程序是否符合要求。
- 边缘情况测试 :应用程序应具备足够的健壮性,能够处理随机和意外事件。可以使用 Android SDK 附带的 Monkey 和 monkeyrunner 工具,以随机和可重现的方式对应用程序进行压力测试。
2.6 最大化测试覆盖率
虽然实现 100% 的测试覆盖率不现实,但目标是尽可能在多种不同条件下对应用程序进行全面测试。这可能需要在模拟器上使用多个 AVD 进行测试,同时也在多个目标设备上进行测试,并考虑结合使用手动和自动化测试程序。
2.7 管理测试环境
不要认为移动应用程序因为“体积小”、功能少就更容易测试,实际上测试移动应用程序对测试人员来说存在许多独特的挑战,尤其是在配置管理方面。
- 识别和获取目标设备 :尽早确定并获取用于应用程序测试的目标设备非常重要。有时可以直接去商店购买新设备(有时需要新的服务计划),但有时情况会更复杂。一些公司(包括设备制造商)会运营开发者项目和设备实验室,开发者可以通过邮寄、远程(通过互联网)或前往实验室的方式租用特定设备的使用时间,这使开发者无需拥有每一台设备,就能访问各种不同网络上的设备,有些实验室甚至配备了专家来帮助解决特定设备的问题。对于预生产设备,通过开发者项目借用服务从制造商或运营商处获取硬件可能需要数月时间。与运营商的设备借用计划合作并从零售渠道购买设备可能会很繁琐,但有时是必要的,所以不要等到最后一刻才收集所需的测试硬件。需要注意的是,预生产设备的行为不一定与最终面向消费者的生产型号完全相同,为了赶生产期限,功能可能会在最后一刻被削减。
- 应对设备碎片化 :移动应用程序测试人员面临的最大挑战之一是市场上新型 Android 设备的激增,这一问题有时被称为设备碎片化,使得跟踪不同 Android SDK 版本、不同屏幕尺寸、功能和硬件的设备变得越来越复杂。
-
管理设备数据库
:使用数据库来跟踪设备信息,对于开发、测试和营销都很有帮助。数据库可包含以下信息:
- 设备信息(型号、功能、SDK 版本、硬件特性,如设备是否有摄像头或内置键盘)
- 手头拥有的设备(以及设备的归属和存放位置等)
- 针对特定应用程序想要测试的目标设备
- 应用程序销售情况最好的设备
2.8 在模拟器上进行测试
测试团队不可能在每个运营商或每个用户使用应用程序的国家都设置测试环境,在某些情况下,使用 Android 模拟器可以降低成本并提高测试覆盖率。使用模拟器的好处如下:
- 当目标设备不可用(或供应不足)时,可使用 AVD 配置设置快速进行测试
- 模拟尚未上市的设备(如预生产设备)
- 测试在实际设备上不可行或不建议进行的困难或危险场景(如可能损坏设备或违反服务协议的测试)
不过,模拟器只是对通用 Android 设备进行有限的模拟,虽然可以通过 AVD 配置选项将模拟器定制为接近目标设备,但它并不依赖于实际设备的硬件或软件实现。应用程序对硬件功能的依赖越多(如通话、网络、LBS、摄像头、蓝牙、传感器数据等),在实际设备上进行测试就越重要。
2.9 在目标设备上进行测试
“尽早测试、经常测试、在实际设备上测试”,这是移动开发中的重要原则。尽早获取目标设备至关重要,在模拟器上测试有一定帮助,但在实际设备上测试才是关键。实际上,应用程序在模拟器上能正常运行并不意味着在实际设备上也能正常工作,在目标设备上进行测试是确保应用程序正确运行的最可靠方法,因为这是在用户将使用的相同硬件上运行应用程序。
虽然在设备连接电源时进行测试很方便,但大多数用户通常仅使用电池供电。因此,务必拔掉设备电源,按照用户最可能遇到的方式测试应用程序,并特别关注应用程序对电池寿命的影响。
2.10 执行自动化测试
收集应用程序信息并构建自动化测试有助于开发出更优质、更可靠的应用程序。Android SDK 提供了多个与代码诊断相关的包,应用程序诊断主要分为以下三类:
- 记录应用程序的性能或使用统计信息
- 基于 JUnit 框架的自动化测试套件
- 使用 monkeyrunner 工具基于脚本进行自动化测试
2.10.1 记录应用程序信息
可利用 Android 内置的日志类 Log(android.util.Log)实现不同级别的诊断日志记录,可在 Eclipse 中或使用 Android SDK 提供的 LogCat 实用程序监控日志信息的输出。但在发布应用程序之前,别忘了去除任何诊断信息(如日志记录信息),因为这些信息可能会对应用程序的性能产生负面影响。
2.10.2 使用 JUnit 和 Eclipse 进行自动化测试
Android SDK 包含了 JUnit 框架的扩展,用于测试 Android 应用程序。通过创建 Java 测试用例来验证应用程序是否按设计运行,可将自动化测试技术用于单元测试和功能测试,包括用户界面测试。
自动化测试 Android 应用程序的步骤如下:
1. 创建测试项目
- 选择合适的项目,右键单击,选择“Android Tools” -> “New Test Project”。
- 在“Test Target”部分,选择“An Existing Android Project”,并选择要测试的应用程序项目(例如,BTDT_Hour22)。
- 向导会根据测试项目的详细信息填充其余字段,可根据需要修改最终细节(这里使用默认值)。
- 点击“Finish”,新的测试项目将在 Eclipse 包资源管理器中显示。
2. 创建测试用例
以测试由 QuizSettingsActivity 类控制的设置屏幕的昵称字段行为为例:
- 在测试项目的 src 文件夹中,右键单击包名。
- 选择“New” -> “JUnit Test Case”。
- 将“Name”字段设置为 QuizSettingsActivityTests。
- 将“Superclass”字段修改为 android.test.ActivityInstrumentationTestCase2
(忽略“Superclass does not exist”的警告)。
- 将“Class Under Test”字段修改为 com.androidbook.btdt.hour22.QuizSettingsActivity。
- 点击“Finish”。
- 在新创建的文件中,手动添加对 QuizSettingsActivity 的导入语句(或整理导入)。
- 最后,为新创建的类添加以下构造函数:
public QuizSettingsActivityTests() {
super("com.androidbook.triviaquiz22", QuizSettingsActivity.class);
}
- 修改 setUp() 方法,获取昵称 EditText 对象,代码如下:
import com.androidbook.btdt.hour22.R;
...
private EditText nickname;
...
@Override
protected void setUp() throws Exception {
super.setUp();
final QuizSettingsActivity settingsActivity = getActivity();
nickname =
(EditText) settingsActivity.findViewById(R.id.EditText_Nickname);
}
- 编写具体测试方法:
public void testNicknameFieldConsistency() {
SharedPreferences settings =
getActivity().getSharedPreferences(QuizActivity.GAME_PREFERENCES,
Context.MODE_PRIVATE);
String fromPrefs =
settings.getString(QuizActivity.GAME_PREFERENCES_NICKNAME, "");
String fromField = nickname.getText().toString();
assertTrue("Field should equal prefs value",
fromPrefs.equals(fromField));
}
private static final String DEBUG_TAG = "QuizSettingsActivityTests";
private static final String TESTNICK_KEY_PRESSES = "T E S T N I C K ENTER";
// ...
public void testUpdateNickname() {
Log.w(DEBUG_TAG, "Warning: " +
"If nickname was previously 'testnick' this test is invalid.");
getActivity().runOnUiThread(new Runnable() {
public void run() {
nickname.setText("");
nickname.requestFocus();
}
});
sendKeys(TESTNICK_KEY_PRESSES);
SharedPreferences settings =
getActivity().getSharedPreferences(QuizActivity.GAME_PREFERENCES,
Context.MODE_PRIVATE);
String fromPrefs =
settings.getString(QuizActivity.GAME_PREFERENCES_NICKNAME, "");
assertTrue("Prefs should be testnick", fromPrefs
.equalsIgnoreCase("testnick"));
}
-
运行自动化测试
有两种运行测试的方法:- 在 Eclipse 中运行 :最简单的方法是选择“Debug” -> “Debug As” -> “Android JUnit Test”,Eclipse 的控制台视图将显示测试应用程序和被测试应用程序的典型安装进度。若未选择测试项目,Eclipse 可能会尝试将常规应用程序作为 JUnit 测试应用程序运行,导致出现大量警告和错误。为避免此问题,可在 Eclipse 包资源管理器中右键单击项目名称,选择“Debug As” -> “Android JUnit Test”,或者进入“Debug Configurations”菜单,双击“Android JUnit Test”创建新的测试配置,然后填写详细信息。通过 LogCat 视图可查看正常的 Android 调试输出以及测试执行的新输出,JUnit 视图则可总结所有运行的测试及其耗时,并包含任何失败测试的堆栈跟踪信息。
- 在模拟器中运行 :仅在模拟器中可用,启动模拟器上安装的 Dev Tools 应用程序,选择“Instrumentation”。若未安装其他测试,可能会看到 android.test.InstrumentationTestRunner 作为唯一显示的项目,点击它即可启动测试。使用此方法时,除了用户界面测试期间的视觉指示外,查看结果的唯一方法是查看 LogCat 输出。可在测试应用的 AndroidManifest.xml 文件的 instrumentation 部分进行修改,使列表中的项目描述更易理解,例如:
<instrumentation
android:targetPackage="com.androidbook.btdt.hour22"
android:name="android.test.InstrumentationTestRunner"
android:label="BTDT Hour 22 Tests" />
Android SDK 还包含多种可用于执行特定 Android 测试的类,如 ActivityUnitTestCase、ApplicationTestCase、ProviderTestCase2 和 ServiceTestCase 等,此外还有用于提供模拟对象、模拟触摸屏事件等的辅助类,可在 android.test 包中找到这些类的完整文档。
通过全面了解 Android 底层硬件访问和掌握有效的应用程序测试方法,开发者能够开发出更高质量、更受用户欢迎的 Android 应用程序。
深入探索 Android:硬件访问与应用测试全攻略
2.11 添加更多测试
掌握基本的测试方法后,开发者可以利用 Android SDK 提供的更多工具为应用添加更多单元测试。Android SDK 包含多种可用于执行特定 Android 测试的类,具体如下:
| 测试类 | 功能 |
| — | — |
| ActivityUnitTestCase | 类似于前面章节的示例,在较低级别对 Activity 进行测试,可用于单元测试活动的特定方面,如处理 onPause()、调用 onFinished() 等,是测试活动生命周期的好方法。 |
| ApplicationTestCase | 与 ActivityUnitTestCase 类似,允许在完全受控的环境中测试 Application 类。 |
| ProviderTestCase2 | 对内容提供者进行隔离测试。 |
| ServiceTestCase | 对服务进行隔离测试。 |
此外,还有辅助类用于提供模拟对象(即非真实对象,但可用于更好地跟踪对真实对象的调用)、模拟触摸屏事件等实用工具。开发者可以在 android.test 包中找到这些类的完整文档。
3. 总结与问答
在前面的内容中,我们学习了如何从多个方面测试和改进 Android 应用程序,这有助于打造出高质量、精致的产品,赢得用户的喜爱。下面我们通过问答的形式,对一些常见问题进行解答。
3.1 常见问答
-
Q:Android 应用程序有认证计划吗?
A:目前 Android 应用程序没有认证计划,但提供商、运营商和移动应用商店通常会根据自身情况制定应用质量标准。 -
Q:在哪里可以了解更多关于使用 JUnit 创建自动化测试套件的信息?
A:可以访问 JUnit 组织的网站(www.junit.org),或者查找关于 JUnit 的相关书籍。 -
Q:有没有一种简单的方法可以编写脚本来控制模拟器和测试套件,开发一个强大的自动化测试环境?
A:有一个名为 monkeyrunner 的工具,它使用 Python 脚本。可以使用这个测试 API 自动化在模拟器和设备上安装和卸载应用程序,发送按键事件、捕获屏幕截图以及运行 JUnit 测试套件。更多关于 monkeyrunner 工具的信息可在 Android 开发者网站(http://goo.gl/uioB7)上查找。
4. 实践练习
为了帮助大家更好地掌握所学知识,下面提供一些实践练习:
1.
为“Been There, Done That!”应用程序制定一个高级测试计划
- 明确测试目标,例如确保应用程序的稳定性、功能完整性、兼容性等。
- 确定测试范围,包括应用程序的各个功能模块、不同的设备和操作系统版本等。
- 制定测试策略,如采用手动测试和自动化测试相结合的方式。
- 安排测试进度,合理分配时间进行不同类型的测试。
- 定义测试通过标准,明确应用程序需要满足的各项指标。
2.
编写一个测试用例,验证用户的头像是否正确上传
import android.test.ActivityInstrumentationTestCase2;
import com.androidbook.btdt.hour22.UploadAvatarActivity;
import android.widget.ImageView;
public class AvatarUploadTestCase extends ActivityInstrumentationTestCase2<UploadAvatarActivity> {
private UploadAvatarActivity uploadActivity;
private ImageView avatarImageView;
public AvatarUploadTestCase() {
super("com.androidbook.btdt.hour22", UploadAvatarActivity.class);
}
@Override
protected void setUp() throws Exception {
super.setUp();
uploadActivity = getActivity();
avatarImageView = (ImageView) uploadActivity.findViewById(R.id.avatarImageView);
}
public void testAvatarUpload() {
// 模拟头像上传操作
uploadActivity.uploadAvatar("test_avatar.jpg");
// 等待一段时间,确保上传完成
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 验证头像是否正确显示
assertNotNull(avatarImageView.getDrawable());
}
}
-
审查在开始开发 Android 应用程序时遇到的各种协议(如 Android SDK 许可协议和 Google Maps API 条款和条件),确定可能需要进行合规性测试的测试用例
- 对于 Android SDK 许可协议,检查应用程序是否按照协议规定使用 SDK 的功能,是否在规定的范围内分发应用程序等。
- 对于 Google Maps API 条款和条件,验证应用程序是否正确使用地图服务,是否遵守数据使用和展示的规定等。
-
阅读 Android SDK 中提供的 Monkey 测试工具的相关资料(http://goo.gl/5xJlv)
- 了解 Monkey 测试工具的基本原理和使用方法。
- 学习如何使用 Monkey 工具对应用程序进行随机事件测试,以发现潜在的问题。
- 尝试在不同的设备和场景下运行 Monkey 测试,观察应用程序的表现。
-
[高级] 如果你熟悉 Python,并且有兴趣为你的应用开发一个强大的自动化测试系统,可以了解 monkeyrunner 工具(http://goo.gl/uioB7)
- 学习 monkeyrunner 工具的基本语法和功能。
- 尝试编写 Python 脚本,使用 monkeyrunner 工具实现自动化安装、卸载应用程序,发送按键事件、捕获屏幕截图等操作。
- 结合 JUnit 测试框架,构建一个完整的自动化测试系统。
通过以上的学习和实践,开发者可以更深入地了解 Android 应用程序的硬件访问和测试方法,不断提升应用程序的质量和用户体验。在实际开发过程中,要根据应用的特点和需求,灵活运用各种测试方法和工具,确保应用程序在不同的设备和环境下都能稳定、高效地运行。
graph LR
A[实践练习] --> B[制定测试计划]
A --> C[编写头像上传测试用例]
A --> D[审查协议确定测试用例]
A --> E[阅读 Monkey 测试工具资料]
A --> F[高级:使用 monkeyrunner 开发自动化测试系统]
超级会员免费看
35

被折叠的 条评论
为什么被折叠?



