Android Espresso试用小结

      昨天把GATC2014的视频看了,发现Google终于会继续更新Espresso了,正好总结一下以前试用的心得。

      照着官方指南(https://code.google.com/p/android-test-kit/wiki/Espresso)搭好环境,可能要翻墙,不过百度也能搜到一些配置的文章。遇到两个问题:一是报错Dex Loader Unable to execute dex: Multiple dex files define什么的,这个是因为其他project里面包含了guava的jar包,我把重复的删掉了,也可以不用集成jar包,每个都去下最新的;二是报错Dex Loader Unable to execute dex: Cannot merge new index 65780 into a non-jumbo instruction!,在project.properties里面添加dex.force.jumbo=true就行了。

      测试的app里面是一层层的folder,里面一个个的document,这些都是用ListView显示的,Espresso提供了通过position点击的API。

1 public void clickOnList(int position) {
2     onData(Matchers.anything())
3     .inAdapterView(withId(android.R.id.list))
4     .atPosition(position)
5     .perform(ViewActions.click());
6 }
View Code

      但是这样很不方便,因为我可能希望通过匹配名称或路径来点击,或者我希望点击后得到名称或者路径。名称数据是存储在JSONObject里面的,我可以先找到AdpterView,通过遍历adapter来获取text对应的position,然后再用Espresso提供的API来点击。

 1 public static int position;
 2 
 3 public void FolderDocument (String text) {
 4     onView(withId(android.R.id.list)).check(ViewAssertions.matches(FolderDocumentData(Matchers.is(text))));
 5     clickOnList(position);
 6 }
 7 
 8 public static Matcher<View> FolderDocumentData(final Matcher<String> dataMatcher) {
 9 
10     return new TypeSafeMatcher<View>() {
11 
12         public void describeTo(Description description) {
13              description.appendText("project document data: ");
14              dataMatcher.describeTo(description);
15         }
16 
17         @Override
18         public boolean matchesSafely(View view) {
19             if (!(view instanceof AdapterView)) {
20                 return false;
21             }
22             adapter = ((AdapterView) view).getAdapter();
23             for (int i = 0; i < adapter.getCount(); i++) {
24                 android.util.Log.i("Hailin", adapter.getItem(i).toString());
25                 JSONObject a = (JSONObject) adapter.getItem(i);
26                 try {
27                     if (dataMatcher.matches(a.getString("n"))) {
28                         position = i;
29                         return true;
30                     }
31                 } catch (JSONException e) {
32                     // TODO Auto-generated catch block
33                     e.printStackTrace();
34                 }
35         }
36           return false;
37         }
38     };
39 }
View Code

      为了避免固定时间的空等以及长时间的render较大document,需要等待标志document render完成的View出现,并且Main Thread的状态为idle,然后再进行后续操作。下面为接口ViewAction的实现。

 1 public static ViewAction waitView(final Matcher<View> matcher, final long millis) {
 2     return new ViewAction() {
 3         @Override
 4         public Matcher<View> getConstraints() {
 5             return isRoot();
 6         }
 7 
 8         @Override
 9         public String getDescription() {
10             return "wait for a specific view during " + millis + " millis.";
11         }
12 
13         @Override
14         public void perform(final UiController uiController, final View view) {
15             uiController.loopMainThreadUntilIdle();
16             final long startTime = System.currentTimeMillis();
17             final long endTime = startTime + millis;
18 
19             do {
20                 for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
21                     // found view with required ID
22                     if (matcher.matches(child)) {
23                         return;
24                     }
25                 }
26 //            uiController.loopMainThreadUntilIdle();
27                 uiController.loopMainThreadForAtLeast(50);
28             }
29             while (System.currentTimeMillis() < endTime);
30 
31             // timeout happens
32             Log.i("Exception", "document/report execution times out");
33         }
34     };
35 }
View Code

      有时候打开document的时候会弹出提示的dialog,为了保证automation能持续跑下去,可以匹配后点掉。

 1 public static ViewAction checkUnexpectedView(final Matcher<View> matcher) {
 2     return new ViewAction() {
 3         @Override
 4         public Matcher<View> getConstraints() {
 5             return isRoot();
 6         }
 7 
 8         @Override
 9         public String getDescription() {
10             return "check whether there is an unexpected view.";
11         }
12 
13         @Override
14         public void perform(final UiController uiController, final View view) {
15             uiController.loopMainThreadUntilIdle();
16             
17             for (View child : TreeIterables.breadthFirstViewTraversal(view)) {
18                 // found view with required ID
19                 if (matcher.matches(child)) {
20                     UnexpectedViewFlag = true;
21                     return;
22                 }
23             }
24 //        uiController.loopMainThreadUntilIdle();
25             uiController.loopMainThreadForAtLeast(50);
26         }
27     };
28 }
View Code

      针对Phone和Tablet的不同,我需要给app设置orientation。

 1 if (isTablet(mActivity)) {
 2     onView(isRoot()).perform(setOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE));
 3 } else {
 4     onView(isRoot()).perform(setOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT));
 5 }
 6 
 7 public static boolean isTablet(Context context) {
 8     return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
 9 }
10 
11 public static ViewAction setOrientation(final int orientation) {
12     return new ViewAction() {
13         @Override
14         public Matcher<View> getConstraints() {
15             return isRoot();
16         }
17 
18         @Override
19         public String getDescription() {
20             return "check orientation";
21         }
22 
23         @Override
24         public void perform(final UiController uiController, final View view) {
25             uiController.loopMainThreadUntilIdle();
26             
27             final Activity activity = (Activity) view.getContext();
28             activity.setRequestedOrientation(orientation);
29             uiController.loopMainThreadForAtLeast(50);
30         }
31     };
32 }
View Code

      测试时还有些其他问题:为了覆盖所有document,必须要遍历;测试跑出crash,需要设置skip list;crash后重启略过之前的跑过的document;跑测试的时候通过socket实时发log。这些跟Espresso无关,在这就不写了。

转载于:https://www.cnblogs.com/RussellWestbrook/p/4123069.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值