如果遇到“强制关闭或ANR”,Android UiAutomator会如何表现

时间:2015-06-22 11:05:16

标签: android ui-automation android-uiautomator

是Android UiAutomator的新手,我能够通过脚本开发验证一些测试,想知道 1)当被测试的应用程序获得“强制关闭”或“ANR”时,会发生什么或UIautomator如何处理/表现 2)请告诉我们是否应该采取任何具体措施来解决这个问题?如果强制关闭或ANR发生,剩下的脚本会继续执行吗?

先谢谢

2 个答案:

答案 0 :(得分:1)

崩溃对话框在阻止测试找到预期的UI元素时会出现问题。但是,如果您可以关闭对话框,那么您的测试可以继续运行(只要您的测试在与被杀死的测试不同的过程中运行)。

困难的部分是这些对话框可以在测试执行期间的任何时候出现。为此原因创建的UiWatcher类。对于使用UiDevice.registerWatcher(..)注册的每个观察者,UiAutomator将在找不到对象时调用checkForCondition()方法。这使您有机会检测崩溃对话框并将其解除,而不会影响您的测试。

答案 1 :(得分:1)

Here为ANR / CRASH UiWatchers的实现提供了很好的参考。

/*
 * Copyright (C) 2013 The Android Open Source Project
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.android.uiautomator.common;

import android.util.Log;
import com.android.uiautomator.core.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UiWatchers {
  private static final String LOG_TAG = UiWatchers.class.getSimpleName();
  private final List<String>  mErrors = new ArrayList<String>();

  /**
   * We can use the UiDevice registerWatcher to register a small script to be
   * executed when the framework is waiting for a control to appear. Waiting may
   * be the cause of an unexpected dialog on the screen and it is the time when
   * the framework runs the registered watchers. This is a sample watcher
   * looking for ANR and crashes. it closes it and moves on. You should create
   * your own watchers and handle error logging properly for your type of tests.
   */
  public void registerAnrAndCrashWatchers() {

    UiDevice.getInstance().registerWatcher("ANR", new UiWatcher() {
      @Override
      public boolean checkForCondition() {
        UiObject window = new UiObject(new UiSelector()
            .className("com.android.server.am.AppNotRespondingDialog"));
        String errorText = null;
        if (window.exists()) {
          try {
            errorText = window.getText();
          } catch (UiObjectNotFoundException e) {
            Log.e(LOG_TAG, "dialog gone?", e);
          }
          onAnrDetected(errorText);
          postHandler();
          return true; // triggered
        }
        return false; // no trigger
      }
    });

    // class names may have changed
    UiDevice.getInstance().registerWatcher("ANR2", new UiWatcher() {
      @Override
      public boolean checkForCondition() {
        UiObject window = new UiObject(new UiSelector().packageName("android")
            .textContains("isn't responding."));
        if (window.exists()) {
          String errorText = null;
          try {
            errorText = window.getText();
          } catch (UiObjectNotFoundException e) {
            Log.e(LOG_TAG, "dialog gone?", e);
          }
          onAnrDetected(errorText);
          postHandler();
          return true; // triggered
        }
        return false; // no trigger
      }
    });

    UiDevice.getInstance().registerWatcher("CRASH", new UiWatcher() {
      @Override
      public boolean checkForCondition() {
        UiObject window = new UiObject(new UiSelector()
            .className("com.android.server.am.AppErrorDialog"));
        if (window.exists()) {
          String errorText = null;
          try {
            errorText = window.getText();
          } catch (UiObjectNotFoundException e) {
            Log.e(LOG_TAG, "dialog gone?", e);
          }
          onCrashDetected(errorText);
          postHandler();
          return true; // triggered
        }
        return false; // no trigger
      }
    });

    UiDevice.getInstance().registerWatcher("CRASH2", new UiWatcher() {
      @Override
      public boolean checkForCondition() {
        UiObject window = new UiObject(new UiSelector().packageName("android")
            .textContains("has stopped"));
        if (window.exists()) {
          String errorText = null;
          try {
            errorText = window.getText();
          } catch (UiObjectNotFoundException e) {
            Log.e(LOG_TAG, "dialog gone?", e);
          }
          onCrashDetected(errorText);
          postHandler();
          return true; // triggered
        }
        return false; // no trigger
      }
    });

    Log.i(LOG_TAG, "Registed GUI Exception watchers");
  }

  public void registerAcceptSSLCertWatcher() {
    UiDevice.getInstance().registerWatcher("SSLCERTERROR", new UiWatcher() {
      @Override
      public boolean checkForCondition() {
        UiObject continueButton = new UiObject(new UiSelector()
          .className("android.widget.Button").packageName("com.android.browser").text("Continue"));
        if (continueButton.exists()) {
          try {
            continueButton.click();
            return true; // triggered
          } catch (UiObjectNotFoundException e) {
            Log.e(LOG_TAG, "Exception", e);
          }
        }
        return false; // no trigger
      }
    });

    Log.i(LOG_TAG, "Registered SSL Certificate Error Watchers");
  }

  public void onAnrDetected(String errorText) {
    mErrors.add(errorText);
  }

  public void onCrashDetected(String errorText) {
    mErrors.add(errorText);
  }

  public void reset() {
    mErrors.clear();
  }

  public List<String> getErrors() {
    return Collections.unmodifiableList(mErrors);
  }

  /**
   * Current implementation ignores the exception and continues.
   */
  public void postHandler() {
    // TODO: Add custom error logging here

    String formatedOutput = String.format("UI Exception Message: %-20s\n",
        UiDevice.getInstance().getCurrentPackageName());
    Log.e(LOG_TAG, formatedOutput);

    UiObject buttonOK = new UiObject(new UiSelector().text("OK").enabled(true));
    // sometimes it takes a while for the OK button to become enabled
    buttonOK.waitForExists(5000);
    try {
      buttonOK.click();
    } catch (UiObjectNotFoundException e) {
      Log.e(LOG_TAG, "Exception", e);
    }
  }
}

基于相同的概念,您可以处理其他常见系统/第三方弹出窗口。

// Common buttons that we can handle.
public static final String[] COMMON_BUTTONS = {
        "OK", "Cancel", "Yes", "No", "Dismiss"
};

public static boolean handleCommonDialog() {
    UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    UiObject button = null;
    for (String keyword : Config.COMMON_BUTTONS) {
        button = device.findObject(new UiSelector().text(keyword).enabled(true));
        if (button != null && button.exists()) {
            break;
        }
    }
    try {
        // sometimes it takes a while for the OK button to become enabled
        if (button != null && button.exists()) {
            button.waitForExists(5000);
            button.click();
            return true; // triggered
        }
    } catch (UiObjectNotFoundException e) {
    }
    return false; // no trigger
}