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:用于声明方法,表示忽略该测试案例。
我们来看一个完整简单案例
Utils文件内容为
我们运行测试案例集合,并查看日志
看完LOG,那么问题来了~
Test Case的执行顺序是如何决定的?
默认情况下,是按照Test Case名称的HASH值进行排序。若HASH值相同,则以字母字典顺序执行。
当然Test Case的执行顺序,也可使用Annotation来指定。
(7)@FixMethodOrder(order):用于修饰测试案例集合类(class)。order有三种取值:MethodSorters.DEFAULT(默认方式),MethodSorters.NAME_ASCENDING(字母字典方式),MethodSorters.JVM(由JVM自己决定)。
这里我们看一下字母字典方式执行顺序。
JVM顺序方式,存在一定的随机性,通常不做考虑。
在本地做了几次JVM顺序的执行,发现每次的执行顺序都与NAME_ASCENDING一致。可能不同的JVM不同,或者存在其他影响因素,这里不再深究。有知晓的同学,还望指点。
我们来做一下扩展~
(8)@Test(timeout=XXX):用于声明方法,该方法必须在XXX毫秒内完成,否则视为失败测试案例。
我们对Test Case1进行修改
运行,并查看LOG和结果
可见,IDE是将测试案例完全执行完毕后,再与Timeout进行比对,判断测试案例是否成功。
当然,我们可以通过,修改timeout(Long型),或减少任务量等方式,将Test Case成功执行。这里不再啰嗦。
(9)@Test(expected=XXException.class):用于声明方法,该方法应当抛出XXException异常,若未抛异常或抛出其他异常,则视为失败测试案例。
我们队Test Case3进行修改
运行,并查看LOG和结果
我们可以手动抛出异常,使得测试案例成功执行。
至此,常用的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介绍完毕。若有遗漏,之后再做补充。
相关文章推荐
- UIAutomator2.0详解(IDE View篇)
- UIAutomator2.0详解(UIDevice篇----截屏)
- UIAutomator2.0详解(UIDevice篇----Screen操作)
- UIAutomator2.0详解(UIDevice篇----获取控件)
- UIAutomator2.0详解(UIDevice篇----触屏操作2)
- UIAutomator2.0详解(入门篇)
- UIAutomator2.0详解(UIDevice篇----UIWatcher)
- UIAutomator2.0详解(UIDevice篇----Wait)
- UIAutomator2.0详解(UIDevice篇----performActionAndWait)
- UIAutomator2.0详解(UIDevice篇----waitForWindowUpdate)
- UIAutomator2.0详解(UIDevice篇----LastTraversedText质疑)(未解)
- UIAutomator2.0详解(UIDevice篇----Hierarchy)
- UIAutomator2.0详解(UIDevice篇---- 序)
- UIAutomator2.0详解(By & BySelector & UIObject2 VS UISelector & UIObject)
- 详解使用Spring Security OAuth 实现OAuth 2.0 授权
- Retrofit 2.0 注解分类详解
- Java单元测试工具:JUnit4(三)——JUnit详解之运行流程及常用注解
- vue2.0之axios使用详解
- 详解vue之页面缓存问题(基于2.0)
- 2.0-tar打包工具详解