您的位置:首页 > 产品设计 > UI/UE

UIAutomator2.0详解(JUnit Annotation篇)

2017-10-25 00:21 309 查看
在入门篇,我们提到了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: case1
I/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: case1
I/APPUITest: index=1
...
I/APPUITest: index=99
I/APPUITest: closeAPP
I/APPUITest: destroy:


org.junit.runners.model.TestTimedOutException: test timed out after 1 milliseconds
at 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: case3
I/APPUITest: closeAPP
I/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介绍完毕。若有遗漏,之后再做补充。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息