UIAutomator2.0详解(JUnit Annotation篇)

来源:互联网 发布:遍历二维数组 编辑:程序博客网 时间:2024/06/05 20:54

在入门篇,我们提到了UIAutomator2.0与1.0的不同。其中,2.0基于JUnit,使用Annotation声明测试案例,是一个重要的特点。本篇将通过实例来讲述几个常用Annotation的使用。

不论何种测试,都需要初始化平台环境,遍历测试案例,为每个测试案例初始化测试上下文,并按照一定的顺序执行测试。
Annotation也是一样的思路。

(1)@BeforeClass:用于声明方法,该方法将在测试案例集(class)实例创建前执行。因此,该方法必须为static类型,仅被执行一次。相当于初始化测试平台环境。

(2)@AfterClass:用于声明方法,该方法将在测试案例集合(class)实例销毁前执行。因此,该方法也必须为static类型,仅被执行一次,相当于清理测试平台环境。

(3)@Before:用于声明方法,该方法将在每个测试案例(function)被调用前执行,因此,该方法可根据测试案例数量,被多次执行,相当于初始化测试上下文。

(4)@After:用于声明方法,该方法将在每个测试案例(function)被调用后执行,因此,该方法可根据测试案例数量,被多次执行,相当于清理测试上下文。

(5)@Test:用于声明方法,该方法将被视为测试案例(function)被执行。

(6)@Ignore:用于声明方法,表示忽略该测试案例。

我们来看一个完整简单案例

RunWith(AndroidJUnit4.class)public class SalaryShowAppTest {    private static final String TAG="APPUITest";    private String mPackageName="com.breakloop.salaryshow";    private String mLaunchActivityName=".MainActivity";    public  static UiDevice mDevice;    @BeforeClass    public static void init(){        Log.i(TAG, "init ");        mDevice=UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());    }    @Before    public void OpenAPP(){        Log.i(TAG, "OpenAPP ");        try {            if(!mDevice.isScreenOn()){  //唤醒屏幕                mDevice.wakeUp();            }        } catch (RemoteException e) {            e.printStackTrace();        }        Utils.startAPP(mPackageName);  //启动app        mDevice.waitForWindowUpdate(mPackageName, 2 * 2000);    }    @Test    public void case1(){        Log.i(TAG, "case1 ");    }    @Test    public void case3(){        Log.i(TAG, "case3 ");    }    @Test    public void case20(){        Log.i(TAG, "case20 ");    }    @Test    public void case21(){        Log.i(TAG, "case21 ");    }    @Test@Ignore    public void case5(){        Log.i(TAG, "case5 ");    }    @After    public void closeAPP(){        Log.i(TAG, "closeAPP ");        Utils.closeAPP(mDevice,mPackageName);    }    @AfterClass    public static void destroy(){        Log.i(TAG, "destroy ");        mDevice=null;    }}

Utils文件内容为

public class Utils {    public static void  startAPP(String sPackageName){        Context mContext = InstrumentationRegistry.getContext();        Intent myIntent = mContext.getPackageManager().getLaunchIntentForPackage(sPackageName);  //启动app        mContext.startActivity(myIntent);    }    public static void closeAPP(UiDevice uiDevice, String sPackageName){        try {            uiDevice.executeShellCommand("am force-stop "+sPackageName);        } catch (IOException e) {            e.printStackTrace();        }    }    public static void startAPP(UiDevice uiDevice,String sPackageName, String sLaunchActivity){        try {            uiDevice.executeShellCommand("am start -n "+sPackageName+"/"+sLaunchActivity);        } catch (IOException e) {            e.printStackTrace();        }    }}

我们运行测试案例集合,并查看日志

I/APPUITest: init I/APPUITest: OpenAPP I/APPUITest: case20 I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case21 I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case1 I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case3 I/APPUITest: closeAPP I/APPUITest: destroy

看完LOG,那么问题来了~
Test Case的执行顺序是如何决定的?
默认情况下,是按照Test Case名称的HASH值进行排序。若HASH值相同,则以字母字典顺序执行。

当然Test Case的执行顺序,也可使用Annotation来指定。
(7)@FixMethodOrder(order):用于修饰测试案例集合类(class)。order有三种取值:MethodSorters.DEFAULT(默认方式),MethodSorters.NAME_ASCENDING(字母字典方式),MethodSorters.JVM(由JVM自己决定)。

这里我们看一下字母字典方式执行顺序。

I/APPUITest: init I/APPUITest: OpenAPP I/APPUITest: case1I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case20 I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case21 I/APPUITest: closeAPP I/APPUITest: OpenAPP I/APPUITest: case3 I/APPUITest: closeAPP I/APPUITest: destroy

JVM顺序方式,存在一定的随机性,通常不做考虑。
在本地做了几次JVM顺序的执行,发现每次的执行顺序都与NAME_ASCENDING一致。可能不同的JVM不同,或者存在其他影响因素,这里不再深究。有知晓的同学,还望指点。

我们来做一下扩展~

(8)@Test(timeout=XXX):用于声明方法,该方法必须在XXX毫秒内完成,否则视为失败测试案例。

我们对Test Case1进行修改

    @Test(timeout = 1)    public void case1(){        Log.i(TAG, "case1: ");        for (int index=1;index<100;index++){            Log.i(TAG, "index="+index);        }    }

运行,并查看LOG和结果

I/APPUITest: init I/APPUITest: OpenAPP I/APPUITest: case1I/APPUITest: index=1...I/APPUITest: index=99I/APPUITest: closeAPPI/APPUITest: destroy: 
org.junit.runners.model.TestTimedOutException: test timed out after 1 millisecondsat android.util.Log.println_native(Native Method)at android.util.Log.i(Log.java:180)...Tests ran to completion.

可见,IDE是将测试案例完全执行完毕后,再与Timeout进行比对,判断测试案例是否成功。
当然,我们可以通过,修改timeout(Long型),或减少任务量等方式,将Test Case成功执行。这里不再啰嗦。

(9)@Test(expected=XXException.class):用于声明方法,该方法应当抛出XXException异常,若未抛异常或抛出其他异常,则视为失败测试案例。

我们队Test Case3进行修改

    @Test(expected = IOException.class)    public void case3(){        Log.i(TAG, "case3: ");    }

运行,并查看LOG和结果

I/APPUITest: init I/APPUITest: OpenAPP I/APPUITest: case3I/APPUITest: closeAPPI/APPUITest: destroy
java.lang.AssertionError: Expected exception: java.io.IOException...Tests ran to completion.

我们可以手动抛出异常,使得测试案例成功执行。

    @Test(expected = IOException.class)    public void case3() throws IOException {        Log.i(TAG, "case3: ");        throw new IOException();    }

至此,常用的Annotation介绍完毕。若有遗漏,之后再做补充。

阅读全文
0 0
原创粉丝点击