• 手机自动化测试:appium源码分析之bootstrap三


    手机自动化测试:appium源码分析之bootstrap三

     

    研究bootstrap源码,我们可以通过代码的结构,可以看出来appium的扩展思路和实现方式,从中可以添加我们自己要的功能,针对appium进行定制,poptest在2015年10月24日开设appium的课程,课程采用真实的商业项目进行培训,用现在互联网金融的业务。
    bootstrap代码中io.appium.android.bootstrap.handler包中的类都是对应的指令类,核心都是execute方法。

    下面我们看下HashMap:
    private static HashMap<String, CommandHandler> map = new HashMap<String, CommandHandler>();

    static {
    map.put("waitForIdle", new WaitForIdle());
    map.put("clear", new Clear());
    map.put("orientation", new Orientation());
    map.put("swipe", new Swipe());
    map.put("flick", new Flick());
    map.put("drag", new Drag());
    map.put("pinch", new Pinch());
    map.put("click", new Click());
    map.put("touchLongClick", new TouchLongClick());
    map.put("touchDown", new TouchDown());
    map.put("touchUp", new TouchUp());
    map.put("touchMove", new TouchMove());
    map.put("getText", new GetText());
    map.put("setText", new SetText());
    map.put("getName", new GetName());
    map.put("getAttribute", new GetAttribute());
    map.put("getDeviceSize", new GetDeviceSize());
    map.put("scrollTo", new ScrollTo());
    map.put("find", new Find());
    map.put("getLocation", new GetLocation());
    map.put("getSize", new GetSize());
    map.put("wake", new Wake());
    map.put("pressBack", new PressBack());
    map.put("dumpWindowHierarchy", new DumpWindowHierarchy());
    map.put("pressKeyCode", new PressKeyCode());
    map.put("longPressKeyCode", new LongPressKeyCode());
    map.put("takeScreenshot", new TakeScreenshot());
    map.put("updateStrings", new UpdateStrings());
    map.put("getDataDir", new GetDataDir());
    map.put("performMultiPointerGesture", new MultiPointerGesture());
    map.put("openNotification", new OpenNotification());
    }

    appium底层调用的是uiautomator的api。我们看下click动作:
    package io.appium.android.bootstrap.handler;

    import com.android.uiautomator.core.UiDevice;
    import com.android.uiautomator.core.UiObjectNotFoundException;
    import io.appium.android.bootstrap.*;
    import org.json.JSONException;

    import java.util.ArrayList;
    import java.util.Hashtable;

    /**
    * This handler is used to click elements in the Android UI.

    * Based on the element Id, click that element.

    */
    public class Click extends CommandHandler {

    /*
    * @param command The {@link AndroidCommand}

    * @return {@link AndroidCommandResult}

    * @throws JSONException

    * @see io.appium.android.bootstrap.CommandHandler#execute(io.appium.android.
    * bootstrap.AndroidCommand)
    */
    @Override
    public AndroidCommandResult execute(final AndroidCommand command)
    throws JSONException {
    if (command.isElementCommand()) {
    try {
    final AndroidElement el = command.getElement();
    el.click();
    return getSuccessResult(true);
    } catch (final UiObjectNotFoundException e) {
    return new AndroidCommandResult(WDStatus.NO_SUCH_ELEMENT,
    e.getMessage());
    } catch (final Exception e) { // handle NullPointerException
    return getErrorResult("Unknown error");
    }
    } else {
    final Hashtable<String, Object> params = command.params();
    final Double[] coords = { Double.parseDouble(params.get("x").toString()),
    Double.parseDouble(params.get("y").toString()) };
    final ArrayList<Integer> posVals = absPosFromCoords(coords);
    final boolean res = UiDevice.getInstance().click(posVals.get(0),
    posVals.get(1));
    return getSuccessResult(res);
    }
    }
    }
    该类中的方法处理点击事件,首先方法会判断你传入的命令参数是针对控件对象的还是坐标的
    如果参数是控件,会获得命令中的控件对象,然后调用click方法
    AndroidElement.java
    public boolean click() throws UiObjectNotFoundException {
    return el.click();
    }

    在代码中el如下定义:private final UiObject el; 
    说明调用的是uiautomator中的UiObject类的click方法,click方法的作用就是点击该控件中心,点击完成后调用getSuccessResult
    /**
    * Returns success along with the payload.

    * @param value
    * @return {@link AndroidCommandResult}
    */
    protected AndroidCommandResult getSuccessResult(final Object value) {
    return new AndroidCommandResult(WDStatus.SUCCESS, value);
    }
    创建AndroidCommandResult新对象,传入WDStatus.SUCCESS,和value(我们这里传入的值为true).首先看一下SUCCESS的值,该值存放在枚举类WDStatus中。
    SUCCESS (0, "The command executed successfully."), 
    下面进入AndroidCommandResult类的构造方法里。
    JSONObject json;
    public AndroidCommandResult(final WDStatus status, final Object val) {
    json = new JSONObject();
    try {
    json.put("status", status.code());
    json.put("value", val);
    } catch (final JSONException e) {
    Logger.error("Couldn't create android command result!");
    }
    }
    构造方法里把传入的参数保存在了json对象中,以键值对的形式。好了,条件为控件的情况分析结束,下面开始分析坐标。
    坐标

    如果是坐标的话,程序会获得命令里的坐标参数,保存在Double数组中。
    final Hashtable<String, Object> params = command.params();
    final Double[] coords = { Double.parseDouble(params.get("x").toString()),
    Double.parseDouble(params.get("y").toString()) };

    接下来会通过absPosFromCoords方法将Double转换为List。所以下面来看absPosFromCoords方法的实现:
    /**
    * Given a position, it will return either the position based on percentage
    * (by passing in a double between 0 and 1) or absolute position based on the
    * coordinates entered.

    * @param coordVals
    * @return ArrayList<Integer>
    */
    protected static ArrayList<Integer> absPosFromCoords(final Double[] coordVals) {
    final ArrayList<Integer> retPos = new ArrayList<Integer>();
    final UiDevice d = UiDevice.getInstance();

    final Double screenX = (double) d.getDisplayWidth();
    final Double screenY = (double) d.getDisplayHeight();

    if (coordVals[0] < 1 && coordVals[1] < 1) {
    retPos.add((int) (screenX * coordVals[0]));
    retPos.add((int) (screenY * coordVals[1]));
    } else {
    retPos.add(coordVals[0].intValue());
    retPos.add(coordVals[1].intValue());
    }

    return retPos;
    }
    首先会判断传入的坐标是以百分比的形式还是以坐标的形式。如果是百分比说明你传入的不是绝对坐标,而是相对坐标,这种情况你就需要获取屏幕的尺寸,然后和百分比做计算得到当前屏幕中你所要点击的坐标点。如果传入的是坐标,那就直接将Double类型的值转化为Int的值。
    经过上面的一番操作以后,会得到确切坐标值保存在数组中返回。
    然后程序调用UiDevice的click方法点击啦:
    final boolean res = UiDevice.getInstance().click(posVals.get(0), posVals.get(1)); 
    最后返回一个成功的AndroidCommandResult对象。

  • 相关阅读:
    VirtualBox-5.0.16设置windows与ubuntu的共享文件夹
    ubuntu普通账户获取root权限的方法以及su和su -的区别
    9、redis之事务2-Jedis的八种调用方式(事务、管道、分布式)介绍
    8、redis之事务1-redis命令
    3、redis之java client环境搭建
    2、redis原生的命令操作不同数据类型
    如何用消息系统避免分布式事务
    Caffe学习系列(1):安装配置ubuntu14.04+cuda7.5+caffe+cudnn
    caffe windows学习:第一个测试程序
    caffe windows 学习第一步:编译和安装(vs2012+win 64)
  • 原文地址:https://www.cnblogs.com/poptest/p/4949782.html
Copyright © 2020-2023  润新知