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

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

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

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

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

共收到 26 条回复 时间 点赞

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

React Native?

jack #23 · 2019年07月17日 Author
e4rljia 回复

抱歉写错了,是 react-native

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

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

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

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

jack 回复

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

jack 回复

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

jack #18 · 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 #13 · 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 回复

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

jack 回复

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

jack #10 · 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 回复

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

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

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

jack 回复

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

jack #6 · 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 #3 · 2019年07月19日 Author
cmlanche 回复

没用 appium espresso, 用的原生的 espresso

jack 回复

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

jack 回复

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

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