自动化测试中短信验证码的动态获取方案
在移动端或Web端UI自动化测试中,登录环节经常遇到短信验证码,而测试环境往往无法使用固定万能码。为了解决这一问题,可以通过在Android设备上部署一个轻量级应用,实时拦截短信并写入本地文件,然后在测试脚本中借助ADB读取文件内容,解析出最新的验证码并自动填入输入框。
整体思路
方案分为两部分:
- Android端:编写一个具有短信接收权限的APK,监听系统广播,将收到的短信时间与内容追加写入手机存储的固定文件(如
/sdcard/smslog.txt)。 - 测试脚本端:通过ADB命令读取该文件,提取最后一行中包含的验证码数字,并传递给自动化测试框架(如Selenium)进行输入。
Android端实现
核心组件是一个BroadcastReceiver,在接收到android.provider.Telephony.SMS_RECEIVED广播后,从Intent中解析出短信内容,并写入文件。以下是重写后的关键代码:
public class SmsReceiver extends BroadcastReceiver {
private static final String FILE_NAME = "smslog.txt";
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault());
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null || !Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
return;
}
StringBuilder messageBody = new StringBuilder();
Bundle bundle = intent.getExtras();
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus != null) {
for (Object pdu : pdus) {
SmsMessage sms = SmsMessage.createFromPdu((byte[]) pdu);
messageBody.append(sms.getMessageBody());
}
}
}
String logEntry = DATE_FORMAT.format(new Date()) + " " + messageBody.toString() + "\n";
writeToFile(context, logEntry);
}
private void writeToFile(Context context, String content) {
File logFile = new File(Environment.getExternalStorageDirectory(), FILE_NAME);
try (FileOutputStream fos = new FileOutputStream(logFile, true)) {
fos.write(content.getBytes());
} catch (IOException e) {
Log.e("SmsReceiver", "Write failed", e);
}
}
}
在AndroidManifest.xml中注册接收器并声明权限:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
...>
<receiver android:name=".SmsReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
将APK安装到测试手机,并在系统设置中授予该应用短信读取和存储权限,确保其可以在后台持续运行。
验证文件生成
安装并触发短信后,通过ADB检查文件内容,确认记录正常:
adb shell cat /sdcard/smslog.txt
输出示例:
2023-08-15-14-23-10 您好,您的验证码为7959
2023-08-15-14-24-05 您好,您的验证码为6474
Python脚本端集成
在自动化测试脚本中,使用subprocess执行ADB命令,读取文件最后一行并提取连续的数字序列作为验证码。优化后的函数如下:
import subprocess
import re
def fetch_verification_code():
adb_cmd = "adb shell cat /sdcard/smslog.txt"
result = subprocess.run(adb_cmd, shell=True, capture_output=True, text=True)
lines = result.stdout.strip().split('\n')
if not lines:
raise Exception("短信日志文件为空")
last_line = lines[-1]
# 提取最后一组连续数字作为验证码
match = re.search(r'\d{4,6}', last_line)
if match:
return match.group()
raise Exception("未能从短信中提取验证码")
获取到验证码后,即可在Selenium或其他自动化框架中定位输入框并填入,完成登录流程。
注意事项
- Android 6.0及以上需要动态申请
RECEIVE_SMS和WRITE_EXTERNAL_STORAGE权限,可在应用启动时引导用户授权。 - 若使用Android 10+分区存储,建议将文件写入应用的专属外部存储目录,避免权限问题。
- 确保测试手机与执行ADB的宿主机通过USB连接,且ADB调试已授权。
