APPIUM Version: 1.6.3
JAVA Client: 5.0.0
JAVA: 1.8
UiAutomator2 Drvier: 0.2.6
//capabilities
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
//click the button to verify the toast message
driver.findElementByXPath("//*[contains(@text,'Button')]").click();
WebDriverWait wait = new WebDriverWait(driver, 10);
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(@text, 'port')]")))
Toast.makeText(getBaseContext(), "Change port successfully", Toast.LENGTH_SHORT).show();
使用 uiautomator2 启动应用是成功的,点击也是成功的,但是尝试验证 Toast 消息时,没有成功过。错误信息如下:
org.openqa.selenium.TimeoutException: Expected condition failed: waiting for presence of element located by: By.xpath: //*contains(@text, 'port')
手机中有安装两个应用:
//同样的代码,定位符改成一个Button的定位符,是能找到的
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@text='Button']")));

源码打开后,这里的红色标记怎么解决啊,没有任何报错啊,编译也没有问题
@Test
public void toastVerificationTest() throws JSONException {
    getUiDevice().waitForIdle();
    scrollTo("Views"); // Due to 'Views' option not visible on small screen
    waitForElement(By.accessibilityId("Views"), 10 * SECOND);
    click(findElement(By.accessibilityId("Views")));
    scrollTo("Popup Menu");
    waitForElement(By.accessibilityId("Popup Menu"), 10 * SECOND);
    click(findElement(By.accessibilityId("Popup Menu")));
    waitForElement(By.accessibilityId("Make a Popup!"), 10 * SECOND);
    click(findElement(By.accessibilityId("Make a Popup!")));
    waitForElement(By.xpath(".//*[@text='Search']"), 10 * SECOND);
    click(findElement(By.xpath(".//*[@text='Search']")));
    waitForMilliSeconds(500);
    element = findElement(By.xpath("//*[@text='Clicked popup menu item Search']"));
    String toastMSG = getText(element);
    assertEquals("Clicked popup menu item Search", toastMSG);
    Logger.info("[AppiumUiAutomator2Server]", " findElement By.xpath: " + element);
    assertTrue(By.xpath("//*[@text='Clicked popup menu item Search']") + "not found", isElementPresent(element));
    click(findElement(By.accessibilityId("Make a Popup!")));
    waitForElement(By.xpath(".//*[@text='Add']"), 10 * SECOND);
    click(findElement(By.xpath(".//*[@text='Add']")));
    waitForMilliSeconds(500);
    element = findElement(By.xpath("//*[contains(@text,'Clicked popup menu item Add')]"));
    Logger.info("[AppiumUiAutomator2Server]", " findElement By.xpath: " + element);
    assertTrue(By.xpath("//*[@text='Clicked popup menu item Add']") + "not found", isElementPresent(element));
    toastMSG = getText(element);
    assertEquals("Clicked popup menu item Add", toastMSG);
    click(findElement(By.accessibilityId("Make a Popup!")));
    waitForElement(By.xpath(".//*[@text='Edit']"), 10 * SECOND);
    click(findElement(By.xpath(".//*[@text='Edit']")));
    waitForMilliSeconds(500);
    element = findElement(By.xpath("//*[@text='Clicked popup menu item Edit']"));
    Logger.info("[AppiumUiAutomator2Server]", " findElement By.xpath: " + element);
    assertTrue(By.xpath("//*[@text='Clicked popup menu item Edit']") + "not found", isElementPresent(element));
    toastMSG = getText(element);
    assertEquals("Clicked popup menu item Edit", toastMSG);
    click(findElement(By.xpath(".//*[@text='Share']")));
    waitForMilliSeconds(1000);
    element = findElement(By.xpath("//*[@text='Clicked popup menu item Share']"));
    Logger.info("[AppiumUiAutomator2Server]", " findElement By.xpath: " + element);
    assertTrue(By.xpath("//*[@text='Clicked popup menu item Share']") + "not found", isElementPresent(element));
    toastMSG = getText(element);
    assertEquals("Clicked popup menu item Share", toastMSG);
}
单元测试执行方法:
am instrument -w -e class io.appium.uiautomator2.unittest.test.HandlersTest#toastVerificationTest io.appium.uiautomator2.e2etest.test/android.support.test.runner.AndroidJUnitRunner
单元测试日志:
04-20 12:08:19.134  6055  6068 I appium  : [AppiumUiAutomator2Server] Starting S
erver
04-20 12:08:19.379  6055  6068 I appium  : [AppiumUiAutomator2Server] waiting fo
r app to launch
04-20 12:08:30.028  6055  6068 I appium  : [AppiumUiAutomator2Server] findElemen
t By.xpath: {"sessionId":":sessionId","status":0,"value":{"ELEMENT":"f2e952ea-d5
0c-4b4b-a81e-c1244240c30d"}}
04-20 12:08:32.122  6055  6068 I appium  : [AppiumUiAutomator2Server] findElemen
t By.xpath: {"sessionId":":sessionId","status":0,"value":{"ELEMENT":"4e141e0b-a5
3a-4e46-82d4-cec7cd748640"}}
04-20 12:08:34.646  6055  6068 I appium  : [AppiumUiAutomator2Server] findElemen
t By.xpath: {"sessionId":":sessionId","status":0,"value":{"ELEMENT":"3a16e7f8-86
2d-453e-90be-d70eec2bb85b"}}
04-20 12:08:36.705  6055  6068 I appium  : [AppiumUiAutomator2Server] findElemen
t By.xpath: {"sessionId":":sessionId","status":0,"value":{"ELEMENT":"9fc430ea-19
d5-44cd-b121-031275152d9b"}}
从日志来看,单元测试执行时,是有找到 toast 元素的,但是我在 eclipse 里面写测试用例的时候就是报没有找到,真是头疼
private class Listener extends Thread{
        private long previousTime = currentTimeMillis();
        public void run() {
            while (true) {
                AccessibilityEvent accessibilityEvent = null;
                toastMessages = init();
                //return true if the AccessibilityEvent type is NOTIFICATION type
                UiAutomation.AccessibilityEventFilter eventFilter = new UiAutomation.AccessibilityEventFilter() {
                    @Override
                    public boolean accept(AccessibilityEvent event) {
                        return event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
                    }
                };
                Runnable runnable = new Runnable() {
                    @Override
                    public void run() {
                        // Not performing any event.
                    }
                };
                try {
                    //wait for AccessibilityEvent filter
                    accessibilityEvent = UiAutomatorBridge.getInstance().getUiAutomation()
                            .executeAndWaitForEvent(runnable /*executable event*/, eventFilter /* event to filter*/, 500 /*time out in ms*/);
                } catch (Exception ignore) {}
                if (accessibilityEvent != null) {
                    toastMessages = accessibilityEvent.getText();
                    previousTime = currentTimeMillis();
                    Logger.info("toastMessages:" + toastMessages);
                    GetToastMessage.toastMessage = toastMessages.toString();// add by carl
                }
                if(stopLooping){
                    break;
                }
            }
        }
引用 uiautomator2.0 server 的相关 jar,不要引 android.jar,json jar: json-20070829.jar
try {
            Runtime.getRuntime().exec("adb forward tcp:"+ 8201 +" tcp:6790");
            Thread.sleep(2000);
            String sessionId = "";
            //create session
            sessionId = TestHelper.post("/wd/hub/session", new JSONObject().put("desiredCapabilities", new JSONObject()).toString());
            System.out.println(sessionId);
            if (sessionId.contains("sessionId")) {
                sessionId = new JSONObject(sessionId).getString("sessionId");
                System.out.println("sessionId:" + sessionId);
            } else {
                sessionId = "c04ada9b-38cf-4778-9168-12faf6747159";
            }
//          System.out.println(TestHelper.get("/wd/hub/session/" + sessionId + "/getPostMsg"));
//          System.exit(1);
            String elementId = "";
            //find element: Make a Popup!
            JSONObject element = new JSONObject("{\"strategy\":\"xpath\",\"selector\":\"//*[contains(@text,'Make a Popup!')]\",\"context\":\"\",\"multiple\":false}");
            elementId = TestHelper.post("/wd/hub/session/" + sessionId + "/element", element.toString());
            System.out.println("elementId:" + elementId);
            elementId = new JSONObject(elementId).getJSONObject("value").getString("ELEMENT");
            //click one element
            JSONObject click = new JSONObject().put("elementId", elementId);
            TestHelper.post("/wd/hub/session/" + sessionId + "/element/" + elementId + "/click", click.toString());
            TestHelper.waitTimes(2000);
            elementId = TestHelper.post("/wd/hub/session/" + sessionId + "/element", new JSONObject("{\"strategy\":\"xpath\",\"selector\":\"//*[@text='Search']\",\"context\":\"\",\"multiple\":false}").toString());
            System.out.println("elementId:" + elementId);
            elementId = new JSONObject(elementId).getJSONObject("value").getString("ELEMENT");
            //click one element
            TestHelper.post("/wd/hub/session/" + sessionId + "/element/" + elementId + "/click", new JSONObject().put("elementId", elementId).toString());
            for (int i=0; i<2000; i++) {
                elementId = TestHelper.post("/wd/hub/session/" + sessionId + "/element", new JSONObject("{\"strategy\":\"xpath\",\"selector\":\"//*[@text='Clicked popup menu item Search']\",\"context\":\"\",\"multiple\":false}").toString());
                if (!elementId.contains("not")) {
                    System.out.println("i=" + i);
                    System.out.println("elementId:" + elementId);
                    elementId = new JSONObject(elementId).getJSONObject("value").getString("ELEMENT");
                    System.out.println(TestHelper.get("/wd/hub/session/" + sessionId + "/element/" + elementId+ "/attribute/text"));
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
这绝对是个坑,不过让我学习了 uiautomator2.0 drvier server 的原代码,和 uiautomator1.0 不一样,有点意思。
本人做的改动主要包含:
package io.appium.uiautomator2.handler;
import io.appium.uiautomator2.handler.request.SafeRequestHandler;
import io.appium.uiautomator2.http.AppiumResponse;
import io.appium.uiautomator2.http.IHttpRequest;
import io.appium.uiautomator2.server.WDStatus;
import io.appium.uiautomator2.utils.Logger;
public class GetToastMessage extends SafeRequestHandler {
    public static String toastMessage = "defalut value is null";//值由GetToastMessage.toastMessage = toastMessages.toString();// add by carl这句更新
    public GetToastMessage(String mappedUri) {
        super(mappedUri);
    }
    @Override
    public AppiumResponse safeHandle(IHttpRequest request) {
        Logger.info("GetToastMessage command");
        return new AppiumResponse(getSessionId(request), WDStatus.SUCCESS, toastMessage);
    }
}
    
     