在做自动化测试的时候,我们遇到接电话的case。这个问题的难点在于要自动的实现某一个时刻有电话打进来才能起作用。像我上篇文章写的case,是一个接电话的case,那么要想让该case起作用,我就得启动case后,手动拨一个电话给该手机。这不叫自动化,只能称为半自动化。那么有没有办法能让某个手机在莫个时间准确的打个电话过来。
思路1
用框架去控制2台手机,告诉其中一台手机给另一台手机打个电话,用我们自研的框架可以实现这个功能。但是问题在于现在不能通过调用API来获取手机号啦,那么如果这么做的话,就得每次手动填写手机号。可能对做APP测试的公司也没太大问题,但是如果是测手机的,手机型号就有很多种,那么sim卡也是很多的,要是每次都填写手机号,是不可行的。所以这个方法在研究了一下午后被我放弃了。
思路2
现在获取手机号的方式有2种,一种发短信给10086,但是不是所有运营商的手机都可以。那么打电话算最靠谱了吧。所以我们需要一个机器来接受来电,然后记录下来电号码,暂且称该手机为总机。只要给总机拨个电话,那么总机就能知道手机号了。如果这个时候,再回拨给该手机,也就是实现了在某个时刻准确的打个电话过来。
所以得在总机上安装个apk,用BroadcastReceiver来处理这种需求。
apk
public class PhoneReceiver extends BroadcastReceiver {
private static final String TAG = "PhoneReceiver";
private String lastIncomingNumber;
private Context context;
private boolean hasCallBack = false;
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "接收到广播 : " + intent.getAction());
// 如果是去电
this.context = context;
if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.d(TAG, "call OUT:" + phoneNumber);
} else {
TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
PhoneStateListener listener = new PhoneStateListener() {
@Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.d(TAG, "电话状态发生改变" + incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.d(TAG, String.format("电话状态变为空闲"));
if (!hasCallBack && lastIncomingNumber != null && lastIncomingNumber.length() != 0) {
hasCallBack = true;
Log.d(TAG, String.format("已挂断和 %s 的通话", lastIncomingNumber));
Intent phoneIntent = new Intent("android.intent.action.CALL", Uri.parse("tel:" + lastIncomingNumber));
phoneIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(phoneIntent);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d(TAG, String.format("收到%s的来电", incomingNumber));
hasCallBack = false;
lastIncomingNumber = incomingNumber;
break;
}
}
};
}
主要的类就是上面的PhoneReceiver广播接收者。来电的时候,我们记录下电话号码,等该来电挂断以后,立即回拨给对方。配置文件如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tm"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.tm.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".PhoneReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
</application>
</manifest>
这样我们就让该总机做到了立即回拨的功能。
缺点
1.该总机的号码要写死在case里或者case的配置文件里。当总机号码更换以后,用到该号码的case也会变化。当然如果在框架里去实现的话,也很简单。设定一个总机号码配置文档,这样,每次启动uiautomator case的时候,涉及到telephony模块的case都去该文档上读一下该号码即可,当然这得需要框架。
2.相对于APP测试来说,一般是测当在使用APP的过程中来一个电话的处理方式。用上面的方法可能不太好,因为你不能操作的过程中跑去打个电话,太麻烦。但是像我这样测系统的就好多了,因为我会专门测试telephony的功能,这样我就把打电话和接电话一起测了。