Pruebas automatizadas de UI basadas en Appium

Por qué necesita pruebas de automatización de la interfaz de usuario

La aplicación móvil es un sistema complejo, y el acoplamiento entre diferentes funciones es muy fuerte. Es difícil garantizar la función general solo a través de pruebas unitarias. Las pruebas de IU son una parte importante del desarrollo de aplicaciones móviles, pero la velocidad de ejecución es lenta y hay muchas cargas de trabajo repetitivas. Para reducir estas cargas de trabajo y mejorar la eficiencia del trabajo, es necesario introducir soluciones de pruebas automatizadas integradas sostenibles.

Por que elegir Appium

Appium es una herramienta de prueba de código abierto que se puede utilizar para probar aplicaciones nativas y aplicaciones web híbridas en Android / iOS / Windows.

  1. Para hacer frente a la rápida iteración de las funciones de las aplicaciones móviles, cada vez más aplicaciones adoptan un modo híbrido, es decir, algunas funciones se transfieren a la página web incorporada de la aplicación. Appium puede cambiar y probar fácilmente aplicaciones nativas o páginas web integradas en la aplicación, y tiene un buen soporte para la aplicación híbrida.

  2. Appium utiliza el marco de prueba proporcionado por cada plataforma, por lo que no es necesario introducir código de terceros o aplicaciones de reempaquetado.

    plataforma Marco de prueba
    Android 4.2 o superior UiAutomator / UiAutomator2 (predeterminado)
    Android 2.3 o superior Instrumentación (proporcionada por Selendroid)
    iOS 9.3 y superior XCUITest
    Por debajo de iOS 9.3 UIAutomation
  3. Appium es de código abierto en GitHub, se mantiene con frecuencia y la comunidad es relativamente activa. Con los esfuerzos continuos de la comunidad, Appium siempre puede mantener la compatibilidad con la última versión del sistema operativo del teléfono móvil y el marco de prueba oficial, y sus funciones se están volviendo cada vez más completas, incluida la recopilación de registros básicos, la grabación de pantalla, el reconocimiento de imágenes basado en opencv, etc., y recientemente Soporte para IOS 13 / Android 10 agregado por la versión;

  4. Appium admite la búsqueda de elementos a través de complementos personalizados. También hay complementos de terceros que están disponibles en GitHub, como el proyecto de ejemplo de control de reconocimiento de iconos basado en inteligencia artificial. También puede personalizar complementos para buscar elementos de página mediante el reconocimiento de imágenes, OCR y otros métodos.

Use pepino para organizar la caja

Appium admite una variedad de lenguajes de programación, incluidos Java, Python, etc., pero el uso directo del código para mantener el caso es menos legible y el costo de aprendizaje es relativamente alto. La introducción de Cucumber puede organizar el caso de una manera más cercana al lenguaje natural. Cucumber es una herramienta que soporta BDD (Behavior-Driven Development). Puede personalizar la plantilla de reglas gramaticales y convertir los pasos descritos en el texto en pasos que se ejecutan por código. Debido a que Cucumber y Java 8 son compatibles con la codificación de texto en chino, puede personalizar los pasos de operación en chino, que son más fáciles de entender que el código en inglés. Tomando la definición de una operación de clic más básica como ejemplo, la regla gramatical esperada es "当 点击 [元素名称]", puede usar la siguiente definición:

   // Cucumber使用正则表达式匹配引号中的内容作为type参数
   @当("^点击 \"([^\"]*)\"$")
   public void findElementAndClick(String type) throws Throwable {
       // driver为Appium对待测设备的抽象,所有测试步骤最终转为对driver对操作
       // type可以传入元素ID对应的字符串,By.id表示通过元素resource-id查找
       driver.findElement(By.id(type)).click();
   }

Al escribir un caso, utilice el patrón de diseño de objeto de página que se usa comúnmente para las pruebas de automatización de la interfaz de usuario, es decir, defina un objeto de página para la página de la interfaz de usuario que debe probarse en la aplicación, que contiene los elementos operables o verificables en la página y agrega métodos comunes.

Tome la página de inicio de Huajiao como ejemplo, puede crear un nuevo objeto llamado "Página de inicio", que contiene métodos de búsqueda correspondientes a elementos como "Buscar", "Mi" e "Iniciar transmisión" (por ejemplo, el botón de búsqueda, correspondiente al elemento de búsqueda resource-id es com.huajiao:id/main_home_top_search). Dado que ingresar el uid de usuario en la página de búsqueda para buscar es una operación común, puede definir un método de "búsqueda" para esto. Todos los casos de prueba, objetos de página, elementos y métodos se guardan y editan utilizando la página web de fondo de prueba, y se realiza la función básica de finalización de palabras clave.

Defina las operaciones básicas como hacer clic, deslizar e ingresar texto como se indicó anteriormente. Después de establecer la página y el método adecuados, un caso de uso se puede transformar en una descripción de caso cercana a la naturaleza ( #comenzando con una línea de comentario):

# "$首页.搜索"表示使用"首页"Page中的"搜索"元素
当 点击 $首页.搜索
# "$搜索.搜索()"表示调用搜索页面的搜索方法,括号内为搜索关键词参数
$搜索.搜索(43011080)
当 断言元素出现 $搜索.搜索结果

Escriba código para realizar operaciones personalizadas complejas

El uso de Cucumber para definir operaciones comunes, como hacer clic, deslizar, verificar texto, etc., puede reducir la carga de trabajo de escribir un caso de prueba y mejorar la legibilidad del caso de prueba, pero no todas las funciones pueden usar operaciones comunes. Especialmente porque Cucumber solo admite la ejecución ordenada de instrucciones paso a paso y no puede ramificar o repetir instrucciones, por lo que la lógica de operación compleja requiere escribir código en pasos personalizados para completar la operación. La encapsulación de la parte del código se refiere al proyecto Espresso proporcionado oficialmente por Android, y el proceso de "buscar-operar-verificar" se lleva a cabo mediante una llamada en cadena.

Tome el cierre de sesión del cliente de Android como ejemplo, haga clic en el elemento "Inicio-Mi" en la parte inferior. Si el estado actual no es de inicio de sesión, aparecerá una ventana emergente de inicio de sesión. En este momento, el elemento "Inicio-Mi" en la parte inferior no está visible, lo que indica que no ha iniciado sesión. estado.

Debido a que Cucumber se ejecuta de forma secuencial y no se puede realizar "我的"元素可见时退出登陆,不可见时关闭登陆弹窗, debe escribir código para personalizar los pasos de cierre de sesión:

    @当("^退出登录$")
    public void logout() throws Throwable {
        // 点击"首页-我的"
        onView(By.id("com.huajiao:id/bottom_tab_user")).perform(click());
        try {
            // 如果当前用户已登陆,不会弹窗提示登陆,"首页-我的"元素可见
            onView(By.id("com.huajiao:id/bottom_tab_user")).check(matches(isDisplayed()));
            // 调用退出登录的方法
            logOut();
        }
        // 未登录状态,"首页-我的"元素不存在,抛出NoSuchElementException
        catch (NoSuchElementException e) {
            // 点击系统back键关闭登陆弹窗
            onActions().pressKeyCode(AndroidKey.BACK, "1").perform();
        }
    }

Utilice Appium para encontrar elementos de la interfaz de usuario

  1. Método de búsqueda básico

    • By.id: Busque a través del ID de recurso del elemento;
    • MobileBy.AndroidUIAutomator(String code): Búsqueda por texto de código de UIAutomator2. codePara cumplir con el texto del código de la especificación UIAutomator2, Appium analizará el texto y usará la reflexión para llamar a UIAutomator2 para buscar; el siguiente es el uso de los elementos UiSelectorcontenidos texten el texto de búsqueda :String code = "new UiSelector().textContains(\"" + text + "\");";
  2. xpath buscar elementos
    xpath se puede utilizar para buscar elementos y atributos en documentos XML. Appium y la herramienta oficial uiautomatorviewer de Google para obtener elementos están organizados en formato xml, y xpath puede ubicar con precisión elementos By.idque solo By.classNamepueden ubicarse pero no pueden ubicarse:

    • La copia es un elemento hermano del elemento "TEXT" y el ID de recurso del elemento hermano es "ID":
      xpath://*[@text='TEXT')]/../android.widget.TextView[@resource-id='ID']
    • El resource-id es "ID" y el elemento secundario del elemento de estado seleccionado. El atributo attr del elemento secundario es value: xpath://*[@resource-id='ID' and @selected='true']/*[@attr='value']

    Aunque el método xpath es más preciso para buscar elementos, la ruta de los elementos puede verse afectada por cambios de diseño y el rendimiento en iOS no es bueno. Por lo tanto, se recomienda utilizar resource-idmétodos como combinar elementos de posicionamiento primero

  3. Elemento de búsqueda de reconocimiento de imágenes
    Appium admite la búsqueda por imagen en el nivel Por selector By by = MobileBy.image(base64ImageString). Actualmente, no se admite la búsqueda de varios elementos, solo se devuelve el primer elemento encontrado.
    Para que Appium admita la búsqueda de imágenes, se requiere un poco de trabajo preparatorio:

    1. Instale la versión NodeJS de la biblioteca OpenCV:npm install -g opencv4nodejs

    2. Configure los parámetros relacionados en Appium:

      // 设置图片识别阈值,默认0.4。需要尝试在找不到元素和找到不匹配元素间的平衡
      driver.setSetting(Setting.IMAGE_MATCH_THRESHOLD, 0.5);
      // 图片识别耗时较长,可以在操作元素对时候不再次查找图片,以节省时间
      driver.setSetting(Setting.CHECK_IMAGE_ELEMENT_STALENESS, false);
      

StaleElementReferenceException: cuando Appium encuentra un elemento y luego intenta manipularlo, se lanzará StaleElementReferenceExceptionuna excepción si el elemento ya no está en el recurso DOM de la página actual . Cuando Appium usa UIAutomator2 para encontrar elementos, mantendrá la caché de los elementos. Cuando opere en los elementos, pasará directamente la información en caché a UIAutomator2 para hacer clic, deslizar y otras operaciones.

  • En el proceso de prueba real, puede haber pasos: la página A salta a la página B; haga clic en el elemento el en la página B. Ambas páginas A y B tienen elementos con el mismo ID que el. Al intentar manipular el elemento el en la página B, Appium usa directamente el caché de la página A, que aparecerá en este momento StaleElementReferenceException;
  • Dado que Appium usa solicitudes HTTP para buscar y manipular elementos, el proceso real de búsqueda y operación de elementos es: elemento de búsqueda POST -> elemento de caché del servidor -> elemento de caché operativo POST, hay un intervalo de tiempo. También puede deberse a que elementos como ventanas emergentes en el extremo de la APLICACIÓN se bloqueen durante la solicitud de red StaleElementReferenceException.

Flujo de trabajo general

  1. El cliente de htest obtiene la lista de descargas del servidor de empaquetado de Android empaquetado y filtra la última versión del paquete de instalación de APK. Si hay una versión superior a la última versión en el teléfono móvil, la aplicación Huajiao en el teléfono móvil se sobrescribirá y la ejecución del caso de prueba de BVT se activará automáticamente (se activará directamente desde la página web de la plataforma de prueba al ejecutar un solo caso);
  2. La plataforma de prueba selecciona el conjunto de casos de uso de BVT descrito por Cucumber y, al mismo tiempo, encuentra la página de la página, escapa de los elementos y métodos del paso del caso de uso y lo reemplaza con el localizador de elementos que puede usar el cliente (el id:comienzo significa buscar a través de resource-id y el text:comienzo significa buscar a través del contenido de texto ), que se devuelve al cliente a través de una solicitud HTTP (utilizando socket para enviar cuando se ejecuta un caso único).
  3. Durante la ejecución del caso de prueba, puede suceder que la ventana emergente del teléfono móvil cubra el elemento de la APP Huajiao al buscar el elemento. Por lo tanto, durante la ejecución del caso de prueba, detectará la ventana emergente que puede aparecer en el teléfono móvil y no esperada en el paso de prueba. , Incluyendo la primera ventana emergente de carga, la ventana emergente de descarga de regalo de apertura, etc., después de cerrar la ventana emergente, busque el elemento nuevamente;
  4. El cliente htest inicializa el controlador de Appium, usa Appium como proxy para conectarse al teléfono móvil y realiza operaciones básicas en el caso de prueba en el teléfono móvil;
  5. Si falla la ejecución del caso de prueba, intentará volver a ejecutar el caso fallido. Si vuelve a fallar, recopilará registros de teléfonos móviles, guardará capturas de pantalla y grabaciones de pantalla, y guardará el registro fallido en la plataforma de prueba. Utilice socket para enviar los resultados de ejecución al ejecutar un solo caso , El resultado se devuelve a la plataforma de prueba a través del servidor htest para su visualización, si es bvt, los datos del resultado se devuelven a través de la interfaz

Utilice la plataforma de prueba para ejecutar casos de prueba a la vez en la web:


Si intercambia experiencia en pruebas de software, pruebas de interfaz, pruebas automatizadas y entrevistas. Si está interesado, puede agregar comunicación de prueba de software: 1085991341, y habrá intercambios técnicos con colegas.
Dividido por módulos, todo el marco se divide en:

  1. Plataforma de prueba: página web, utilizada para guardar y editar casos de prueba basados ​​en Cucumber, administrar páginas de página, analizar los elementos en los casos de uso y enviar los casos de uso escapados al cliente para mostrar los resultados de ejecución reales del cliente;

  2. htest server: middleware Java, marco netty utilizado, responsable de reenviar los mensajes de socket, es decir, la plataforma de prueba notifica al cliente que ejecute el mensaje del caso de uso y el resultado de la ejecución del cliente vuelve a la plataforma de prueba. utilizar:

    • Inicio de netty en el lado del servidor en htestcom.htest.server.server.BaseServer

      @Overridepublic void run() {
          if (bossGroup == null) {
              bossGroup = new NioEventLoopGroup();
              model.setBossGroup(bossGroup);
          }
          if (workerGroup == null) {
              workerGroup = new NioEventLoopGroup();
              model.setWorkGroup(workerGroup);
          }
          ServerBootstrap b = new ServerBootstrap(); 
          b.group(model.getBossGroup(),model.getWorkGroup())
              .channel(NioServerSocketChannel.class)
              .option(ChannelOption.SO_BACKLOG, 100)
              .option(ChannelOption.SO_KEEPALIVE, true)
              .handler(new LoggingHandler(LogLevel.INFO))
              .childHandler(getChildHandler());
          try {
              future = b.bind(SERVER_IP, getPort()).sync(); 
              LOGGER.debug("服务启动成功 ip={},port={}",SERVER_IP, getPort());
              future.channel().closeFuture().sync();
          } catch (Exception e) {
              LOGGER.error("Exception{}", e);
          } finally {
              Runtime.getRuntime().addShutdownHook(new Thread() {
                  @Override public void run() {
                      shutdown();
                  }
              });
          }
      }
      
    • HttpServer, JarServer y WebsocketServer se inician de la misma manera, la diferencia es que escuchan en diferentes puertos y manejan diferentes manejadores de datos.

    • El procesador de HttpServer es com.htest.server.handler.ServerHttpHandlerque los mensajes de procesamiento se procesan de acuerdo con el protocolo http

      @Override
      protected void messageReceived(ChannelHandlerContext ctx, HttpRequest request) {
          try {
              this.request = request; headers = request.headers();
              if (request.method() == HttpMethod.GET) {
                  QueryStringDecoder queryDecoder = new 
                      QueryStringDecoder(request.uri(), Charset.forName("utf-8")); 
                  Map<String, List<String>> uriAttributes = queryDecoder.parameters(); //此处仅打印请求参数(你可以根据业务需求自定义处理) 
                  for (Map.Entry<String, List<String>> attr : uriAttributes.entrySet()){
                      for (String attrVal : attr.getValue()) {
                          Logs.HTTP.debug(attr.getKey() + "=" + attrVal);
                      }
                  }
              }
              if (request.method() == HttpMethod.POST) {
                  fullRequest = (FullHttpRequest) request;
                  //根据不同的 Content_Type 处理 body 数据
                  dealWithContentType();
              }
              keepAlive = HttpHeaderUtil.isKeepAlive(request);
              writeResponse(ctx.channel(), HttpResponseStatus.OK, "开始执行", keepAlive);
          } catch (Exception e) {
              writeResponse(ctx.channel(), HttpResponseStatus.INTERNAL_SERVER_ERROR, "启动失败", true);
          }
      }
      
    • El procesador de JarServer es com.htest.server.handler.ServerHandlerque los mensajes de procesamiento se procesan de acuerdo con el formato protobuf

      @Override
      protected void handleData(ChannelHandlerContext ctx, MessageModel.Message msg) {
          Connection connection = server.getConnectionManager().get(ctx.channel());
          connection.updateLastReadTime();
          server.getMessageReceiver().onReceive(msg, connection);
      }
      
    • El procesador de WebsocketServer es com.htest.server.handler.ServerChannelHandlerque también procesa mensajes de acuerdo con el formato protobuf. La diferencia con HttpServer es que su ChannelInitializer es diferente

  3. htest client: cliente Java, utilizado para definir los pasos de Cucumber, actualizar el APK del teléfono, inicializar Appium y ejecutar casos de prueba; Uso: ejecutar en la línea de comandos en el lado de java -jar htest-client.jarla PC, el lado de la PC debe tener Appium y el entorno opencv de nodejs, controlado por el archivo de configuración yaml Parámetros finales durante la ejecución de la prueba. Los métodos de trabajo específicos son los siguientes:

    • Función: El jar admite la verificación regular de la última función de apk, que está deshabilitada de forma predeterminada y está habilitada a través de la configuración del archivo yaml. Si se encuentra la última apk, se instalará automáticamente en el teléfono móvil y se enviará una solicitud al servidor web (la plataforma de prueba para la gestión automatizada de casos) para activar la ejecución del conjunto de casos del módulo especificado.
    • Estrategia de descarga: el sistema descarga solo la última apk de forma predeterminada, si el valor de apkVersion en el archivo de configuración de yaml local es mayor que el valor de apkVersion en el servidor. Si es más pequeño que el servidor, no se descargará.
    • Estrategia de instalación: una vez completada la descarga, el nombre de la versión del apk en el teléfono (analizado por aapt) se comparará con el nombre de la versión del apk descargado. Si el apk descargado es nuevo, instálelo, de lo contrario no se instalará. Los parámetros de configuración también se pueden instalar en el teléfono móvil designado.Si solo hay un teléfono móvil, no se requieren parámetros de configuración.
    • Una vez completada la instalación, el valor de apkVersion se actualizará automáticamente para el próximo juicio.
    • Una vez completada la instalación, enviará una solicitud http al servidor web. Una vez que el servidor web la reciba, la activará una vez y la enviará a la tarea actual de configuración de fundas del teléfono móvil. El módulo de configuración de casos específicos se configura mediante el parámetro de modelos y el destinatario de correo se configura a través de correos.
  4. Appium: cliente / servidor NodeJS, utilizado para conectarse al teléfono móvil, a través de UIAutomator2 / XCUITest, realizar operaciones básicas como obtener elementos / hacer clic / deslizar el dedo en el terminal móvil; el
    contenido anterior es el contenido completo de este artículo . Se espera que el contenido anterior sea útil para usted. Los amigos que ayudaron pueden dar me gusta y comentar.

Supongo que te gusta

Origin blog.csdn.net/Chaqian/article/details/106607198
Recomendado
Clasificación