Appium 基于 RN 框架开发的 APP 如何通过 Appium 测试

jack · 2019年07月15日 · 最后由 e4rljia 回复于 2019年07月22日 · 2608 次阅读

最近公司的 app 重构了,使用了 facebook 开源的 react-native 框架,这给自动化团队带来许多麻烦

1、resouce-id 都没有了
2、所有 component 的 clickable 属性都是 false

光这两条基本就宣告了以前的脚本彻底废了,关键是即使重新写脚本,clickable 属性是 false,基本的操作功能都不能进行,怎么写脚本呢?我试了使用 tap 方式,也不好使啊,谁有这方面的经验吗

共收到 26 条回复 时间 点赞
jack #4 · 2019年07月17日 Author
e4rljia 回复

抱歉写错了,是 react-native

jack #6 · 2019年07月17日 Author
cmlanche 回复

appium 应该用的是 UIautomator,我理解你说的获取界面信息的工具是不是类似 uiautomatorview? 另外 espresso 不了解,看说明更像是给开发人员用的吧

jack 回复

是的,类似 UIAutomatorviewer,因为 espresso 获取到的控件信息和 UIAutomator 的不一样了

你们原来用的是 UIAutomator 或者 UIAutomator2 的吧,RN 是基于 webview 的,你用 espresso 来做,可以把它想象成 webui 测试,另外你们需要编写一个获取当前界面信息的工具

React Native?

jack #5 · 2019年07月17日 Author
wing 回复

感谢你的回复,按你的说法,这个是需要开发修改 app 吧,添加 content-desc 属性值,但这也只解决了元素定位的问题吧,clickable=false 这个怎么解呢?

jack 回复

UIAutomator 只是 appium 中的一种技术方案,espresso 和 UIAutomator 是同一层次的东西,你可以去了解下

jack #9 · 2019年07月17日 Author
cmlanche 回复

我现在是可以通过 xpath 定位到元素,但是无论是 click 和 tap 都没有反应,不知道是不是跟 clickable 属性是 false 有关系?是不是用了 RN 框架 clickable 都是 false 了呢?espresso 能解决这个问题吗

jack 回复

是的,appium 使用 UIAutomator 的时候其实还是调用 UIDevice 来做 click 的,它会参考 clickable 这个值去,如果是 false,那就失败了。可以改 appium-android-driver 中 bootstrap 的代码,click 都基于坐标去点击,就是复杂点

jack #11 · 2019年07月17日 Author
cmlanche 回复

通过 TouchAction 的 tap 呢?我试了下面的代码
TouchAction actions =new TouchAction(driver);
actions.tap(PointOption.point(50,120)).waitAction(WaitOptions.waitOptions(Duration.ofSeconds(1))).perform();
但是返回 [debug] [W3C (cb4356b0)] Responding to client with driver.performTouch() result: null

jack 回复

tap 其实就是 click,看源码:

register(postHandler, new Click("/wd/hub/session/:sessionId/appium/tap"));
public class Click extends SafeRequestHandler {

    public Click(String mappedUri) {
        super(mappedUri);
    }

    @Override
    protected AppiumResponse safeHandle(IHttpRequest request) throws JSONException,
            UiObjectNotFoundException {
        JSONObject payload = getPayload(request);
        if (payload.has(ELEMENT_ID_KEY_NAME)) {
            Logger.info("Click element command");
            String id = payload.getString(ELEMENT_ID_KEY_NAME);
            Session session = AppiumUIA2Driver.getInstance().getSessionOrThrow();
            AndroidElement element = session.getKnownElements().getElementFromCache(id);
            if (element == null) {
                return new AppiumResponse(getSessionId(request), WDStatus.NO_SUCH_ELEMENT);
            }
            element.click();
        } else {
            Logger.info("tap command");
            Point coords = new Point(Double.parseDouble(payload.get("x").toString()),
                    Double.parseDouble(payload.get("y").toString()));
            coords = PositionHelper.getDeviceAbsPos(coords);
            final boolean res = getUiDevice().click(coords.x.intValue(), coords.y.intValue());
            return new AppiumResponse(getSessionId(request), res);
        }
        Device.waitForIdle();
        return new AppiumResponse(getSessionId(request), true);
    }
}
jack #13 · 2019年07月18日 Author
cmlanche 回复

那看来只能改用 espresso 了

jack #17 · 2019年07月18日 Author
cmlanche 回复

我试了下打印 pagesource,里面居然出现了 resource-id, resource-id="android:id/action_mode_bar_stub",
resource-id="app:id/action_bar_root" viewIndex="4

jack 回复

谷歌没有这样的工具,只能自己撸。主要是大家对 appium 的使用基本停留在 UIAutomator 上,对 espresso 的开发和了解不多

jack #14 · 2019年07月18日 Author
cmlanche 回复

今天在 GitHub 上看到了这个工程 appium-espresso-driver,看说明貌似是在 appium 中使用 espresson, 但没有使用例子,我只是简单的添加了参数 cap.setCapability("automationName", "Espresso"); 报这个错误 Got an unexpected response: {"id":"26428249-e523-49bd-b144-7bc42d1b3efa","sessionId":null,"status":7,"value":"io.appium.espressoserver.lib.handlers.exceptions.NoSuchElementException: Could not find element with strategy XPATH and selector //android.view.ViewGroup[@index='0']\n\tat io.appium.espressoserver.lib.handlers.FindE..., 这个是不是您说的 espresso 获取到的控件信息和 UIAutomator 的不一样了

jack 回复

再给你推荐一个方案,用你原来的方式找控件,找到后,拿到这个控件的区域,然后用 monkey 去点

jack 回复

因为 espresso 是侵入式的测试方案,获取到的信息是真实的控件信息,而不是由系统解释了一层(UIAutomator 就是这样的),所以兼容性好啊

jack #19 · 2019年07月18日 Author
cmlanche 回复

看了下 espresso 的 demo 视频,执行速度比 appium 要快多了。另外,编写获取当前界面信息的工具,目前我还没这个能力,如果不借助工具呢,如何去获取定位信息呢?要去看 app 的源码吗?google 没有提供类似 UIautomatorview 的工具吗?

jack #21 · 2019年07月19日 Author
cmlanche 回复

今天试着用 espresso 去写脚本,发现它是基于 activity 的,就是每个 test 都会跟一个 activity 绑定吧,代码如下:
@Rule
public ActivityTestRule mLoginActivityTestRule =
new ActivityTestRule(LoginActivity.class);

@Test
public void clickLoginButton_showsSuccessScreenAfterLogin() {
String email = "username@email.com";
String password = "password";

//type in email
onView(withId(R.id.edit_text_email)).perform(typeText(email), closeSoftKeyboard());

//type in password
onView(withId(R.id.edit_text_password)).perform(typeText(password), closeSoftKeyboard());

//click on login button
onView(withId(R.id.button_login)).perform(click());

//verify that success screen shows
String successString = InstrumentationRegistry.getTargetContext().getString(R.string.text_login_successful);
onView(withText(successString)).check(matches(isDisplayed()));

但是我跟 Android 研发同事聊,他们用了 RN 框架后就一个 MainActivity,这样的话是不是 espresso 也不能用了

jack 回复

我没写过 appium espresso 脚本,但我感觉这应该不是,讲道理应该会调用 java-client 的 api 才对

jack 回复

应该来说 appium espresso 也不是针对某个 Activity 的,而是跟 UIAutomator 一样,给控件信息,直接找就完了

jack 回复

我知道,你这个是跟 android app 源代码一块的,可以把它类比为 app 的单元测试

jack 回复

嘿嘿,我就说你写的内个我咋没见过。。。

jack 回复

是的,使用 espresso 的话,整个控件树的信息跟 uiautomatorviewer 完全不一样了

jack #24 · 2019年07月19日 Author
cmlanche 回复

没用 appium espresso, 用的原生的 espresso

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