项目已经做完,这里把在项目中运用到的自动化测试用例的工具类整理出来,以便在以后需要的时候能有迹可循。该工具类是我和我所在的团队人员共同编写,查阅资料来源于互联网,具体来自哪里,由于时间太久了,实在记不得了。小弟第一次写,纯属摸着石头过河,如果有喜欢这篇文字的朋友,请点个赞();如果有所不妥或者冒犯的地方,请。。喷。。轻。。点()。
自动化测试的工具在网上有很多,今天我们就只说Espresso。如果对Espresso还不了解的小伙伴,可以去这里了解一下http://www.jianshu.com/p/ef4ad5424784。
好了,废话不多说,我们直接进入主题:
本次封装主要有四个文件:
BaseView
BaseAction
BaseCheck
BaseObtain
第一个类BaseView
这个类相当于是个基类,在下一步的封装的时候,经常都会用到。
import android.support.annotation.IdRes;
import android.support.test.espresso.DataInteraction;
import android.support.test.espresso.ViewInteraction;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.containsString;
public class BaseView {
/**
* 获取list中的item布局
* @param id list 的ID
* @param itemPosition 第几个item
* @return
*/
public static DataInteraction getListItemView(@IdRes int id, int itemPosition) {
return onData(anything())
.inAdapterView(allOf(withId(id), isDisplayed()))
.atPosition(itemPosition);
}
/**
* 获得某一个view
* @param object 这个view 的ID 或者 这个view上显示的文本
* @return
*/
public static ViewInteraction getView(Object object) {
if(object instanceof String ){
return onView(allOf(withText(containsString((String) object))));
}else if(object instanceof Integer){
return onView(allOf(withId((Integer) object)));
}
return null;
}
}
这两个方法的作用我就不多说了,注释已经写的很清楚了
第二个类BaseAction
这个类中主要是封装了关于动作的一些方法,比如,点击、滑动、输入之类的动作。
import android.os.SystemClock;
import android.support.annotation.IdRes;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.action.MotionEvents;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.espresso.matcher.BoundedMatcher;
import android.support.test.espresso.web.webdriver.Locator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
import android.support.v7.widget.RecyclerView;
import android.text.InputType;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.AdapterView;
import android.widget.EditText;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Assert;
import static android.support.test.espresso.Espresso.onData;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.clearText;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.pressImeActionButton;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.action.ViewActions.swipeDown;
import static android.support.test.espresso.action.ViewActions.swipeLeft;
import static android.support.test.espresso.action.ViewActions.swipeRight;
import static android.support.test.espresso.action.ViewActions.swipeUp;
import static android.support.test.espresso.action.ViewActions.typeText;
import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition;
import static android.support.test.espresso.matcher.ViewMatchers.hasFocus;
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withClassName;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withParent;
import static android.support.test.espresso.web.sugar.Web.onWebView;
import static android.support.test.espresso.web.webdriver.DriverAtoms.findElement;
import static android.support.test.espresso.web.webdriver.DriverAtoms.webClick;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
public class BaseAction {
public static final int LEFT = 1;
public static final int RIGHT = 2;
public static final int DOWN = 3;
public static final int UP = 4;
public static final int INPUTTEXT = 1;
public static final int TYPETEXT = 2;
private static MotionEvent downEvent;
/**
* 单击操作
*/
public static void clickView(Object object) {
clickView(object, false);
}
/**
* 当需要点击的控件在屏幕之外时,调用此方法 isScroll = true
* @param object 控件id 或则 文本
* @param isScroll
*/
public static void clickView(Object object, boolean isScroll) {
doClick(BaseView.getView(object), isScroll);
}
/**
* 长按操作
* @param object
*/
public static void longClickView(Object object) {
doLongClick(BaseView.getView(object));
}
/**
* 输入文本操作
*/
public static void inputText(Object id, String text) {
doInputText(BaseView.getView(id), text);
}
/**
* 输入文本之后点击键盘的回车键
* @param id
* @param text
*/
public static void inputTextIme(Object id, String text){
BaseView.getView(id).perform(click(),clearText(), replaceText(text), pressImeActionButton(),closeSoftKeyboard());
}
/**
* touch事件,按下和抬起 :比如发送语音的时候
* @param id
* @param x
* @param y
* @param duration 触摸时长
*/
public static void touchViewDU(Object id,int x,int y,int duration){
BaseView.getView(id).perform(touchDownAndUp(x,y,duration));
}
/**
*不带坐标的 touch事件,默认为 (0,0)点
* @param id 被触摸的控件ID或则文本
* @param action 触摸事件:MotionEvent.ACTION_DOWN,MotionEvent.ACTION_UP,MotionEvent.ACTION_MOVE,MotionEvent.ACTION_CANCEL
*/
public static void touchView(Object id,int action){
touchView(id,0,0,action);
}
/**
* 带坐标的touch事件
* @param id
* @param x
* @param y
* @param action
*/
public static void touchView(Object id,float x,float y,int action){
BaseView.getView(id).perform(touch(x, y, action));
}
public static ViewAction touchDownAndUp(final float x, final float y, final int duration) {
return new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "Send touch events.";
}
@Override
public void perform(UiController uiController, final View view) {
// Get view absolute position
int[] location = new int[2];
view.getLocationOnScreen(location);
// Offset coordinates by view position
float[] coordinates = new float[]{x + location[0], y + location[1]};
float[] precision = new float[]{1f, 1f};
// Send down event, pause, and send up
MotionEvent down = MotionEvents.sendDown(uiController, coordinates, precision).down;
uiController.loopMainThreadForAtLeast(duration);
MotionEvents.sendUp(uiController, down, coordinates);
}
};
}
public static ViewAction touch(final float x, final float y, final int action) {
return new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "Send touch events.";
}
@Override
public void perform(UiController uiController, final View view) {
// Get view absolute position
int[] location = new int[2];
view.getLocationOnScreen(location);
// Offset coordinates by view position
float[] coordinates = new float[]{x + location[0], y + location[1]};
float[] precision = new float[]{1f, 1f};
// Send down event, pause, and send up
switch (action){
case MotionEvent.ACTION_DOWN:
downEvent = MotionEvents.sendDown(uiController, coordinates, precision).down;
break;
case MotionEvent.ACTION_MOVE:
MotionEvents.sendMovement(uiController,downEvent,coordinates);
break;
case MotionEvent.ACTION_UP:
MotionEvents.sendUp(uiController,downEvent,coordinates);
break;
case MotionEvent.ACTION_CANCEL:
MotionEvents.sendCancel(uiController,downEvent);
break;
}
}
};
}
/**
* 滑动操作,比如viewpager的左右滑动
* @param id 需要滑动的控件
* @param dir 滑动方向 left = 1,right = 2,down = 3,up = 4
*/
public static void swipe(Object id, int dir) {
ViewAction viewAction = null;
switch (dir) {
case LEFT:
viewAction = swipeLeft();
break;
case RIGHT:
viewAction = swipeRight();
break;
case UP:
viewAction = swipeUp();
break;
case DOWN:
viewAction = swipeDown();
break;
}
BaseView.getView(id).perform(viewAction);
}
/**
* spinner 点击,根据item的文本点击
* @param str
*/
public static void clickSpinnerItem(String str) {
onData(allOf(is(instanceOf(String.class)), is(str))).perform(click());
}
/**
* spinner 点击,根据item的index点击
* @param index
*/
public static void clickSpinnerItem(int index) {
ViewInteraction appCompatCheckedTextView = onView(
allOf(withId(android.R.id.text1),
childAtPosition(
allOf(withClassName(is("com.android.internal.app.AlertController$RecycleListView")),
withParent(withClassName(is("android.widget.FrameLayout")))),
index),
isDisplayed()));
appCompatCheckedTextView.perform(click());
}
/**
* 点击 list item
* @param id list的ID
* @param itemPosition 所要点击的item的index
*/
public static void clickListItem(@IdRes int id, int itemPosition) {
listItemAction(id,itemPosition,click());
}
/**
* 点击list item中的某个控件
* @param id list的ID
* @param child item中需要点击的控件的ID
* @param itemPosition 点击的第几个item
*/
public static void clickListItemChild(@IdRes int id, @IdRes int child, int itemPosition) {
BaseView.getListItemView(id, itemPosition).onChildView(withId(child)).perform(click());
}
public static void inputListItemChild(@IdRes int id, @IdRes int child, int itemPosition, final int flag, String content) {
BaseView.getListItemView(id, itemPosition).onChildView(withId(child)).perform(clearText(), new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "";
}
@Override
public void perform(UiController uiController, View view) {
if(view instanceof EditText){
if (flag == TYPETEXT) {
((EditText) view).setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
}
}, flag == TYPETEXT ? typeText(content) : replaceText(content), closeSoftKeyboard());
}
/**
* list item 长按操作
* @param id list ID
* @param itemPosition item所在的index
*/
public static void longClickListItem(@IdRes int id, int itemPosition) {
listItemAction(id,itemPosition,longClick());
}
private static void listItemAction(@IdRes int id, int itemPosition,ViewAction viewAction){
BaseView.getListItemView(id, itemPosition).perform(viewAction);
}
/**
*查找含有特定规则的list item
* @param var1 adapterBean的class类
* @param match 匹配规则,返回true则找到
* @param class类
*/
public static void clickListItemMatch(Class extends T> var1, MatchBean match){
listItemMatch(var1,match,click());
}
public static void longClickListItemMatch(Class extends T> var1, MatchBean match){
listItemMatch(var1,match,longClick());
}
private static void listItemMatch(Class extends T> var1, MatchBean match, ViewAction viewAction){
onData(withContainTextAdapter(var1,match)).inAdapterView(allOf(isAssignableFrom(AdapterView.class),hasFocus())).perform(viewAction);
}
private static Matcher
针对以上类中的某些方法的用法举例如下:
根据条件匹配点击list的item(RecycleView的用法类似)
BaseAction.clickListItemMatch(Object.class, new BaseAction.MatchBean() {
@Override
public boolean matches(Object object) {
if(你的条件){//条件为真
return true;
}else{
return false;
}
}
});
第三个类BaseCheck
这个类中主要是封装类一些关于文本比较的方法
import android.support.annotation.IdRes;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.rule.ActivityTestRule;
import android.support.test.uiautomator.UiSelector;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Adapter;
import android.widget.AdapterView;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isSelected;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
public class BaseCheck {
/**
* check 某个控件是否显示
*/
@Deprecated
public static void checkDisplay(Object id) {
checkDisplay(id,true);
}
public static void checkDisplay(Object id,boolean check) {
checkWith(id,isDisplayed(),check);
}
/**
* check Toast是否显示文字
* @param text
* @param activityTestRule
*/
public static void checkToast(String text, ActivityTestRule activityTestRule) {
//BaseView.getView(text)
// .inRoot(withDecorView(not(activityTestRule.getActivity().getWindow().getDecorView())))
// .check(matches(isDisplayed()));
}
/**
*check 是否包含某些文字
* @param id
* @param text
*/
public static void checkContainsText(Object id, String text,boolean check) {
checkWith(id,withText(containsString(text)),check);
}
/**
* check list的item布局中的某个控件是否包含文字
* @param id list的ID
* @param child 需要check的那个控件的ID
* @param itemPosition item的index
* @param text 所包含的文字
* @param check 是否包含
*/
public static void checkListChildContainsText(@IdRes int id, @IdRes int child, int itemPosition, String text, boolean check) {
checkListChild(id, child, itemPosition, withText(containsString(text)), check);
}
/**
* check 是否选中
*/
public static void checkSelected(Object id, boolean check) {
checkWith(id,isSelected(),check);
}
/**
* 是否存在
* @param id
* @param check
*/
public static void checkExist(Object id, boolean check){
if(check){
checkWith(id,anyOf(isDisplayed(),not(isDisplayed())),true);
}else{
BaseView.getView(id).check(doesNotExist());
}
}
/**
* list item是否包含某项数据
* @param id
* @param data
* @param check
* @param
*/
public static void checkListContainsText(Object id,MatchListAdapter data,boolean check){
checkWith(id,withAdaptedData(data),check);
}
private static Matcher withAdaptedData(final MatchListAdapter data) {
return new TypeSafeMatcher() {
@Override
public void describeTo(Description description) {
description.appendText("with class name: ");
}
@Override
public boolean matchesSafely(View view) {
if (!(view instanceof AdapterView)) {
return false;
}
@SuppressWarnings("rawtypes")
Adapter adapter = ((AdapterView) view).getAdapter();
for (int i = 0; i < adapter.getCount(); i++) {
if(data.isMatches((T) adapter.getItem(i))){
return true;
}
}
return false;
}
};
}
public interface MatchListAdapter{
boolean isMatches(T item);
}
/**
* 检查recycler是否包含某项数据
*/
public static void checkRecyclerItemContainText(Object id, int itemPosition, final int childId, String text, boolean isCheck){
final View[] childView = {null};
BaseView.getView(id).perform(RecyclerViewActions.actionOnItemAtPosition(itemPosition, new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "";
}
@Override
public void perform(UiController uiController, View view) {
childView[0] =view;
}
}));
}
public static void checkRecyclerText(Object id,MatchListAdapter match,boolean check){
checkWith(id,withRecyclerAdaptedData(match),check);
}
private static Matcher withRecyclerAdaptedData(final MatchListAdapter data) {
return new TypeSafeMatcher() {
@Override
public void describeTo(Description description) {
description.appendText("find recycler view ");
}
@Override
public boolean matchesSafely(View view) {
if (!(view instanceof RecyclerView)) {
return false;
}
for (int i = 0; i < ((RecyclerView) view).getAdapter().getItemCount(); i++) {
if(data.isMatches((T) ((RecyclerView) view).getChildViewHolder((((RecyclerView) view).getChildAt(i))))){
return true;
}
}
return false;
}
};
}
/**
* 原子操作
* @param id
* @param matcher
* @param check
*/
private static void checkWith(Object id,Matcher matcher,boolean check){
if(!check){
matcher=not(matcher);
}
BaseView.getView(id).check(matches(matcher));
}
private static void checkListChild(@IdRes int id, @IdRes int child, int itemPosition, Matcher matcher,boolean check) {
if(!check){
matcher=not(matcher);
}
BaseView.getListItemView(id, itemPosition).onChildView(withId(child)).check(matches(matcher));
}
public static Matcher anyView(){
return anyOf(isDisplayed(),not(isDisplayed()));
}
}
第四个类BaseObtain
这个类第主要作用就是得到控件的某些属性
import android.app.Activity;
import android.support.annotation.IdRes;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.espresso.core.internal.deps.guava.collect.Iterables;
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import android.support.test.runner.lifecycle.Stage;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Adapter;
import android.widget.ListView;
import android.widget.TextView;
import com.bigkoo.pickerview.lib.WheelView;
import org.hamcrest.Matcher;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
public class BaseObtain {
public final static int NOEXISTS = -2;
public final static int YEAR = 1;
public final static int MONTH = 2;
public final static int DAY = 3;
//获取文本
public static String getText(Object id) {
return ((TextView)getRealView(id)).getText().toString();
}
public static String getTimeWheelViewText(Object id, int type) {
if (type == YEAR) {
return (((WheelView)getRealView(id)).getCurrentItem() + 1900) + "";
} else if (type == MONTH || type == DAY) {
if((((WheelView)getRealView(id)).getCurrentItem() + 1) < 10) {
return "0" + (((WheelView)getRealView(id)).getCurrentItem() + 1);
} else {
return (((WheelView)getRealView(id)).getCurrentItem() + 1) + "";
}
}
return "";
}
public static String getListChildText(@IdRes int id, @IdRes int child, int itemPosition) {
final String[] str = new String[1];
BaseView.getListItemView(id, itemPosition).onChildView(withId(child)).perform(new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "get view";
}
@Override
public void perform(UiController uiController, View view) {
str[0] = ((TextView)view).getText().toString();
}
});
if (str[0] == null) {
return "";
}
return str[0];
}
public static int getViewVisibility(Object id) {
int visibility = NOEXISTS;
View view=getRealView(id);
if(view!=null){
visibility=view.getVisibility();
}
return visibility;
}
public static int getListItemCount(Object id) {
View view = getRealView(id);
int count = -1;
if (view instanceof ListView) {
count = ((ListView) view).getAdapter().getCount();
} else if (view instanceof RecyclerView) {
count = ((RecyclerView) view).getAdapter().getItemCount();
}
return count;
}
public static Adapter getListData(Object id) {
return ((ListView) getRealView(id)).getAdapter();
}
public static RecyclerView getRecylerData(Object id) {
return (RecyclerView) getRealView(id);
}
public static RecyclerView.ViewHolder getRecylerItemViewHolder(final Object id, int index){
final View[] view = {null};
BaseView.getView(id).perform(RecyclerViewActions.actionOnItemAtPosition(index, new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "";
}
@Override
public void perform(UiController uiController, View view1) {
view[0] =view1;
}
}));
return getRecylerData(id).getChildViewHolder(view[0]);
}
public static View getRealView(Object id) {
final View[] view = {null};
BaseView.getView(id).perform(new ViewAction() {
@Override
public Matcher getConstraints() {
return BaseCheck.anyView();
}
@Override
public String getDescription() {
return "get view";
}
@Override
public void perform(UiController uiController, View view1) {
view[0] = view1;
}
});
return view[0];
}
public static Activity getCurrentActivity() {
getInstrumentation().waitForIdleSync();
final Activity[] activity = new Activity[1];
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
java.util.Collection activities = ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(Stage.RESUMED);
activity[0] = Iterables.getOnlyElement(activities);
}
});
return activity[0];
}
}
getTimeWheelViewText() 用例:
String year = BaseObtain.getTimeWheelViewText(com.bigkoo.pickerview.R.id.year, BaseObtain.YEAR);
本次封装到此就告一段落了。如果发现不对的地方还请提出来,我会尽快改正。
此文为原创,转载请表明出处!