#

总览

Name Location Description
libmock_ril hardware\ril\mock-ril A mock ril like SecRil.
mockrilcontroller frameworks\opt\telephony\mockril Communicate with libmock_ril,send and receive fake RIL cmd to/from libmock_ril via socket.
TelephonyMockRilTests frameworks\opt\telephony\tests\telephonymockriltests A Package communicates with libmock_ril via mockrilcontroller, it use InstrumentationTestCase framework to test libmock_ril`s mock functions.
FrameworksTelephonyTests frameworks\opt\telephony\tests\telephonytests A Package using InstrumentationTestRunner and TestCase to test Telephony.


上图中,同一层的模块功能相同:

RIL

Reference-ril是Android提供的参考代码。Mock-ril则是一个模拟的Ril模块。三者的功能相同。

Telephony

Telephony和RIL层之间通过Socket通信,mockrilcontroller功能和telephony-common类似,只不过其是与Mock-ril通信。还有一个区别是telephony-common编译为动态库,而mockrilcontroller为静态库

Package

TelephonyMockRilTests 模块中包含静态库mockrilcontroller。通过查看Manifest可以看出TelephonyMockRilTests 测试的目标package是其本身。主要目的是测试mockrilcontroller和Mock-ril模块。
FrameworksTelephonyTests模块中则包含动态库telephony-common,通过查看Manifest可以看出FrameworksTelephonyTests测试的目标package也是其本身。主要目的是测试telephony-common模块。

FrameworksTelephonyTests 分析

根据上一章的测试实例分析,现在来看FrameworksTelephonyTests就不太复杂了。FrameworksTelephonyTests能够同时测试Telephony-common和Mock-ril模块(TelephonyMockRilTests只是对Mock-ril的一个简单测试,在FrameworksTelephonyTests已经覆盖了这部分测试,所以就不再单独分析 TelephonyMockRilTests)。
测试是从TestRunner开始的,FrameworksTelephonyTests新建了一个自定义的TestRunner类TelephonyMockRilTestRunner,用来辅助测试Mock-ril,而对Telephony-common模块的测试,则是直接使用的Android测试框架的的InstrumentationTestRunner。
如下图所示,由于测试用例较多,这里仅挑选2个典型的测试用例进行说明。

GSMPhoneTest

GSMPhoneTest继承了AndroidTestCase类并实现了PerformanceTestCase接口,根据上文可知,AndroidTestCase 继承于JUnit的TestCase,并没有使用Instrumentation框架,所以GSMPhoneTest该用例不能使用Android Instrumentation框架的方法。

1 setUp():

首先初始化GSMTestHandler和GSMPhone对象,得到GSMPhone的引用。并通过GSMPhone对象的方法,注册EVENT_POST_DIAL等一系列事件。

sc = new SimulatedCommands();mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true);

不过新建GSMPhone时,传递的RIL接口是一个模拟的接口,这样在调用GSMPhone方法时,并非调用到正常的RIL.java发送AT指令。而是一个模拟的ril对象SimulatedCommands上。
这样,该测试除了ril接口和调用者是虚拟的,其他Telephony流程和正常流程一致,见下图:

2 testOutgoingCallFailImmediately():

该测试方法用来测试呼出的呼叫立即失败的边缘测试(呼叫还没有出现在call list之前就立即终结),这会导致该失败的呼叫在ForegroundCall list中以IDLE call的形式出现。

public void testOutgoingCallFailImmediately() throws Exception {    Message msg;    mRadioControl.setNextDialFailImmediately(true);    Connection cn = mGSMPhone.dial("+13125551212");    msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);    assertNotNull("Message Time Out", msg);    assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState());    assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());    assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());    assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());    assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());    assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());    assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());    assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());    assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);    assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());}

3 testHangupOnOutgoing:

该测试方法用来测试通话呼出后,在不同状态下(DIALING、ALERTING等)进行挂断。然后判断Phone的状态、Call的状态和连接断开原因是否符合预期。

    public void testHangupOnOutgoing() throws Exception {        Connection cn;        Message msg;        mRadioControl.setAutoProgressConnectingCall(false);        // Test 1: local hangup in "DIALING" state        mGSMPhone.dial("+13125551212");        do {            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));        }        while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING);        cn = mGSMPhone.getForegroundCall().getEarliestConnection();        mGSMPhone.getForegroundCall().hangup();        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);        assertNotNull("Message Time Out", msg);        assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState());        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());        // Test 2: local hangup in "ALERTING" state        mGSMPhone.dial("+13125551212");        do {            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));        } while (mGSMPhone.getState() != PhoneConstants.State.OFFHOOK);        mRadioControl.progressConnectingCallState();        do {            assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));        }        while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);        cn = mGSMPhone.getForegroundCall().getEarliestConnection();        mGSMPhone.getForegroundCall().hangup();        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);        assertNotNull("Message Time Out", msg);        assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState());        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());        assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());        // Test 3: local immediate hangup before GSM index is        // assigned (CallTracker.hangupPendingMO case)        mRadioControl.pauseResponses();        cn = mGSMPhone.dial("+13125551212");        cn.hangup();        mRadioControl.resumeResponses();        msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);        assertNotNull("Message Time Out", msg);        assertEquals(PhoneConstants.State.IDLE, mGSMPhone.getState());        assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());        assertEquals(Connection.DisconnectCause.LOCAL,            mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause());    }

MockRilTest

MockRilTest继承了InstrumentationTestCase类,根据上文可知,InstrumentationTestCase继承于JUnit的TestCase,并使用Instrumentation框架,所以MockRilTest该用例可以使用Android Instrumentation框架的方法。该用例是由自定义的TestRunner——TelephonyMockRilTestRunner运行的。并持有RilChannel对象引用。进而调用RIL层的mock-ril进行测试。

1 setUp():

首先初始化TelephonyMockRilTestRunner和RilChannel对象,得到RilChannel的引用。通过RilChannel的socket和mock-ril进行通信。
如下图所示:


注:聚合关系的方向画错了,暂时没法修改,见谅。

MockRilTest通过RilChannel和mock-ril建立socket连接并通信。MockRilTest的各个测试方法通过Msg类的静态方法,收发RilChannel指令。

        mRunner = (TelephonyMockRilTestRunner)getInstrumentation();        mMockRilChannel = mRunner.mMockRilChannel;

2 testGetRadioState():

  public void testGetRadioState() throws IOException {        log("testGetRadioState E");        Msg.send(mMockRilChannel, 1, 9876, 0, null);        Msg resp = Msg.recv(mMockRilChannel);        //resp.printHeader("testGetRadioState");        assertTrue(String.format("expected cmd == 1 was %d", resp.getCmd()),                resp.getCmd() == 1);        assertTrue(String.format("expected token == 9876 was %d", resp.getToken()),                resp.getToken() == 9876);        assertTrue(String.format("expected status == 0 was %d", resp.getStatus()),                resp.getStatus() == 0);        RilCtrlCmds.CtrlRspRadioState rsp = resp.getDataAs(RilCtrlCmds.CtrlRspRadioState.class);        int state = rsp.getState();        log("testGetRadioState state=" + state);        assertTrue(String.format("expected RadioState >= 0 && RadioState <= 9 was %d", state),                ((state >= 0) && (state <= 9)));        log("testGetRadioState X");    }

3 testStartIncomingCallAndHangup():

public void testStartIncomingCallAndHangup() throws IOException {        log("testStartIncomingCallAndHangup");        RilCtrlCmds.CtrlReqSetMTCall cmd = new RilCtrlCmds.CtrlReqSetMTCall();        String incomingCall = "6502889108";        // set the MT call        cmd.setPhoneNumber(incomingCall);        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_SET_MT_CALL, 0, 0, cmd);        // get response        Msg resp = Msg.recv(mMockRilChannel);        log("Get response status: " + resp.getStatus());        assertTrue("The ril is not in a proper state to set MT calls.",                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);        // allow the incoming call alerting for some time        try {            Thread.sleep(5000);        } catch (InterruptedException e) {}        // we are playing a trick to assume the current is 1        RilCtrlCmds.CtrlHangupConnRemote hangupCmd = new RilCtrlCmds.CtrlHangupConnRemote();        hangupCmd.setConnectionId(1);        hangupCmd.setCallFailCause(16);   // normal hangup        Msg.send(mMockRilChannel, RilCtrlCmds.CTRL_CMD_HANGUP_CONN_REMOTE, 0, 0, hangupCmd);        // get response        resp = Msg.recv(mMockRilChannel);        log("Get response for hangup connection: " + resp.getStatus());        assertTrue("CTRL_CMD_HANGUP_CONN_REMOTE failed",                   resp.getStatus() == RilCtrlCmds.CTRL_STATUS_OK);    }

运行测试

应用编译并安装到目标测试机器中后,通过ADB工具进入终端,通过指令:
am instrument -w com.android.frameworks.telephonytests /android.test.InstrumentationTestRunner
即可运行该测试应用,自动运行每一个测试用例,并将测试结果显示在输出中。如下所示:

com.android.internal.telephony.ATResponseParserTest:.com.android.internal.telephony.AdnRecordTest:.com.android.internal.telephony.ApnSettingTest:Failure in testFromString:junit.framework.AssertionFailedError: expected:<2> but was:<4>        at com.android.internal.telephony.ApnSettingTest.assertApnSettingEqual(ApnSettingTest.java:42)        at com.android.internal.telephony.ApnSettingTest.testFromString(ApnSettingTest.java:93)        at java.lang.reflect.Method.invokeNative(Native Method)        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)        at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1661).com.android.internal.telephony.GsmAlphabetTest:...com.android.internal.telephony.GsmSmsTest:..........Error in testFragmentTurkishText:java.lang.IllegalAccessError: tried to access method com.android.internal.telephony.GsmAlphabet.getEnabledSingleShiftTables:()V from class com.android.internal.telephony.GsmSmsTest        at com.android.internal.telephony.GsmSmsTest.testFragmentTurkishText(GsmSmsTest.java:281)        at java.lang.reflect.Method.invokeNative(Native Method)        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:190)        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:175)        at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1661)...com.android.internal.telephony.IccServiceTableTest:..com.android.internal.telephony.IntRangeManagerTest:.........com.android.internal.telephony.MccTableTest:.....com.android.internal.telephony.NeighboringCellInfoTest:...com.android.internal.telephony.PhoneNumberUtilsTest:..Failure in testCheckAndProcessPlusCode:junit.framework.ComparisonFailure: expected:<[011]8475797000> but was:<[+]8475797000>

总结

作为白盒测试,测试用例的设计至关重要,对于已有的代码,其类与类之间相关性较大的情况,测试用例的设计就会增加复杂度,需要设计多个模拟类来替代相关类,必要时应该在代码设计阶段就应该考虑其可测试性。
大多是先设计测试用例,以测试推进开发。

更多相关文章

  1. tcping测试服务器TCP端口
  2. android handler和message的常用方法
  3. Android通过广播接收者调用服务内方法
  4. Android(安卓)开启关闭软键盘
  5. Android数据库升级、降级、创建(onCreate() onUpgrade() onDowng
  6. RecyclerView的canScrollVertically方法踩坑
  7. Property Anim详解
  8. AndroidGUI13:ViewTreeObserver的常用技巧
  9. onNewIntent 什么时候调用

随机推荐

  1. Open edX数据结构Mysql edxapp
  2. PHPMyWind教程:如何把本地测试好的程序发
  3. MySQL常用的函数
  4. 源码方式安装mysql5.5
  5. 数据库连接“Mysql”丢失,缺少mysql.sock
  6. MySQL查询优化技术讲座
  7. MYSQL简单的binlog恢复测试
  8. 如何从php中的数据库表创建表单下拉列表?
  9. 深入浅出MySQL读书笔记(一)
  10. MySQL搜索优化(用子查询替换长正则表达式)