UiAutomator uiautomator 仿 WebDriver 封装,页面工厂制作,实现多语言定位

小低调 · 2016年07月18日 · 最后由 小低调 回复于 2016年09月10日 · 2130 次阅读
本帖已被设为精华帖!

uiautomator 仿 webdriver 封装,让写代码根据友好,方便
用 uiautomator 也有一段时间了,分享下自己的成果,也希望以 28 原则,让自动化变得更美丽
要是有好的建议,欢迎骚扰

driver 页封装类

private UiDevice driver = null;
public DriverBase(UiDevice uidevice) {
    if (uidevice == null) {
        this.driver = UiDevice.getInstance();
    } else {
        this.driver = uidevice;
    }
}
public UiDevice getDriver() {
    return this.driver;
}
public UiObject findElement(UiSelector by) {
    Logs.logInfo("查找->" + by.toString().substring(10));
    return new UiObject(by);
}
public UiScrollable findElementByscrollable(UiSelector by) {
    Logs.logInfo("查找可滚动->" + by.toString().substring(10));
    return new UiScrollable(by);
}
public UiCollection findElementByUiCollection(UiSelector by) {
    Logs.logInfo("查找->" + by.toString().substring(10));
    return new UiCollection(by);
}

java 注解类

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.TYPE })
public @interface FindBy {
    String id() default "";

    String text() default "";

    int index() default -1;

    String desc() default "";

    Class<?> className() default FindBy.class;

    String checkable() default "";

    int instance() default -1;

}

页面工厂类
每个页面做成一个 page,方便管理,可根据配置,自定义语言

public class HomePage {

    static {
        new PageObjectBase().initElements(HomePage.class);
    }

    @FindByCN(text="你好")
    @FindBy(className = ImageView.class, index = 5, instance = 3)
    public static UiSelector demo01;

    @FindByCN(text = "主页")
    @FindBy(text = "Home")
    public static UiSelector home;

    @FindByCN(text = "我")
    @FindBy(text = "Me")
    public static UiSelector me;

    @FindBy(id = "com.xxxx.xxxxx:id/xxxx")
    public static UiSelector liveMakeup;

    @FindBy(text = "Are you sure you want to quit the application?")
    public static UiSelector exitDialog;

}

利用 java 反射,初始化页面工厂

public class PageObjectBase {

    public void initElements(Class<?> clazz) {
        Field[] field = clazz.getDeclaredFields();
        for (Field f : field) {
            if (Configs.TEST_LANGUAGE.equals("CN")) {
                FindByCN fbCN = f.getAnnotation(FindByCN.class);
                if (fbCN == null) {
                    findByInit(f);
                } else {
                    findByCNInit(f, fbCN);
                }
            } else {
                findByInit(f);
            }
        }
    }
    private void findByCNInit(Field field, FindByCN fb) {
        UiSelector By = new UiSelector();
        try {
            if (fb.text() != "") {
                By = By.text(fb.text());
            }
            if (fb.id() != "") {
                By = By.resourceId(fb.id());
            }
            if (fb.className() != FindBy.class) {
                By = By.className(fb.className());
            }
            if (fb.index() != -1) {
                By = By.index(fb.index());
            }
            if (fb.desc() != "") {
                By = By.description(fb.desc());
            }
            if (fb.checkable() != "") {
                By = By.checkable(Boolean.valueOf(fb.checkable()));
            }
            if (fb.instance() != -1) {
                By = By.instance(fb.instance());
            }

            field.setAccessible(true);
            field.set(this, By);

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
    }

    private void findByInit(Field field) {
        FindBy fb = field.getAnnotation(FindBy.class);
        if (fb == null) {
            return;
        }
        UiSelector By = new UiSelector();
        try {
            if (fb.text() != "") {
                By = By.text(fb.text());
            }
            if (fb.id() != "") {
                By = By.resourceId(fb.id());
            }
            if (fb.className() != FindBy.class) {
                By = By.className(fb.className());
            }
            if (fb.index() != -1) {
                By = By.index(fb.index());
            }
            if (fb.desc() != "") {
                By = By.description(fb.desc());
            }
            if (fb.checkable() != "") {
                By = By.checkable(Boolean.valueOf(fb.checkable()));
            }
            if (fb.instance() != -1) {
                By = By.instance(fb.instance());
            }

            field.setAccessible(true);
            field.set(this, By);

        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
    }

}

TestCase 编写
是不是代码风格跟 WebDriver 一样了

public class Demo01 extends TestCaseBase {
    public void test01() throws UiObjectNotFoundException {
        driver.findElement(HomePage.demo01).click();
        driver.findElement(By.text("测试者")).click();
    }
}

代码写的不是非常好,不要嘲笑,但功能都有了。

共收到 8 条回复 时间 点赞
思寒_seveniruby 将本帖设为了精华贴 07月19日 11:36

加精理由: 巧妙的利用 java 的注解技术对 uiautomator 进行 api 封装. 探索出了对底层库进行更友好封装的一条路. 其实 appium 也是类似这样的实现.

额,有个小问题啊,直接用下面这种方式不是也可以么? 不一定非要注解和反射啊。还是说你根据语言的不同,会有不同的查找方式?所以你用两个注解?

public class LoginPage extends PageObjectBase{

    public static By usernameInput = By.id("username");

@yuncaiwang 主要用来适应不同的语言,做国际化比较方便。以后还可以做成读本地配置文件来对应每个元素定位

TestCaseBase 这个类中封装了什么呢? DriverBase 这个类就是 TestCaseBase 类吗?

匿名 #7 · 2016年08月20日

写的很精值得赞,但是你要考虑到 1 年的测试工程师的能力问题,那就显得还不够,得简单,得可理解,得无学习成本

#7 楼 @sz_mizu TestCaseBase 放着 case 的初始化和监听器

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册