精华内容
下载资源
问答
  • 移动端自动化测试
    2021-09-16 10:02:30

    移动端自动化测试解决方案https://www.alltesting.cn/testservice/ydatplan.htmlicon-default.png?t=L892https://www.alltesting.cn/testservice/ydatplan.html

    背景与问题

    自动化测试https://www.alltesting.cn/jsp/newVersion2/bigNews/alltestingAR.jspicon-default.png?t=L892https://www.alltesting.cn/jsp/newVersion2/bigNews/alltestingAR.jsp是未来发展的趋势,移动端应用的增长,已经超过了PC端的应用。因此,移动端的自动化测试,势在必行

    录制回放工具与测试脚本

    录制回放工具与测试脚本

    通过录制来生成自动化的测试脚本:

    参数化:对脚本进行参数化,可以实现相同的脚本执行不同的数据和测试用例

    测试脚本:定义了整个的测试过程。使用关键字视图的脚本,可以更简单的从手工测试进入自动化测试,避免了学习复杂的编程语言

    专家视图:使用测试脚本来直接编写复杂的逻辑,比如利息计算、手续费计算等检查

    录制工具支持IOS系统和Android系统

    应用支持小程序、APP、H5等

    特殊支持与处理

    支持字符串输入

    支持安全键盘

    支持OCR识别技术

    支持图片相似度对比技术

    基于测试数据模板来设计测试用例

    基于测试数据模板来设计测试用例

    基于数据模板,使用模型驱动的测试用例设计工具,可以实现用例设计的自动化

    主要是规则定义,以及数据正交算法

    测试工具服务化

    测试工具服务化

    通过自动化测试平台,提供了支持不同测试工具的框架,能够把测试工具变成一个一个的服务,提供给外部系统来调用

    批量执行框架

    批量执行框架

    执行框架,支持:

    测试用例的自动分发执行

    预约执行、周期执行

    跨项目的批量执行

    测试日志还记录了测试步骤,特别是对于多个交易/功能的测试用例,可以定位错误

    自动化测试报表

    支持各种统计分析报表,如需求总数和分析、成功失败统计和百分比

    测试用例个数和执行通过的百分比

    测试用例的密度

    自动化测试报表

    更多相关内容
  • 移动端自动化测试

    2022-06-04 15:52:01
    移动端自动化测试

    Java和安卓环境安装和配置

    安装java JDK 并配置环境变量

    1.新建环境变量: JAVA_HOME

    2.新建环境变量: CLASS_PATH: .,%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar(注意最开始那个.)

    3.在PATH里面增加: %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin

    Android环境配置

    1.解压android-sdk-windows.rar

    2.新建环境变量ANDROID_HOME,将压缩的sdk路径配置到该环境变量中

    3.在PATH里面添加: %ANDROID_HOME%\platform-tools;%ANDROID_HOME%\tools;

    adb的基本工作原理

    ADB(android debug brideg)是android平台的调试工具

    ADB包含三部分

    1.Client端:运行在开发机中,即你的开发电脑,用来发送ADB命令

    2.Server端:同样运行在开发机器中,用来管理Client端和手机的Deamon之间的通信

    3.Deamon守护进程:运行在调试设备中,手机或模拟器,用来接受并执行ADB命令

    常用adb命令

     

     

    将手机端的连接写成批处理文件

     

    获取包名和activity名

    包名:package name 用于唯一标识一个app应用(注意不是应用的名字,应用的名字可以相同,但包名一定不同,也不是apk的名字)

    apk: 每一个安卓应用的安卓包后缀叫apk.可以被安装在安卓手机上

    activity名:在Android中每个界面叫一个activity,获取activity名其实就是获取界面名

    应用场景:自动化测试需要通过代码的形式告诉手机测试的是哪个应用的哪个界面,可以通过这个命令进行获取

    步骤:1.先使用adb连接模拟器  2.在命令行中运行命令,获取当前显示的activity的名字:

    adb shell dumpsys window windows | findstr mFocusedApp

    文件传输相关命令

    安装和卸载apk包

    查询本机所有的应用程序包

     查询apk包名和启动activity名字

    截取当前界面

    Appium

    Appium是一个开源、跨平台的自动化测试工具,用于测试原生和轻量移动应用,支持IOS、Android和FirefoxOS平台。Appium驱动Android的UIAutomator框架,使用Selenium的WebDriver JSON协议   Appium测试调用了Selenium的client库使其可以使用任意的语言

    Appium核心是一个web服务器,提供了一套REST接口。它收到客户端的连接,监听到命令,接着在移动设备上执行这些命令,然后将执行结果放到HTTP响应中返还给客户端

    特点:多语言编写测试代码,可以将服务器放在不同的机器上

    Appium环境配置:appium的客户端  appium-python库

    Appium启动设置

    from appium import webdriver

    from appium import  webdriver
    
    desired_cap={}
    
    #必须参数,定义被测脚本的平台属性
    desired_cap['platformName']='Android'
    #必须参数,定义被测手机的安卓版本号(设置->关于本机->android版本,必须跟被测机对得上,不能乱写,大版本不能错,小版本可以不用写)
    desired_cap['platformVersion']='7.1.2'
    #可以写任意的值,但不能为空
    desired_cap['deviceName']='127.0.0.1:62001'
    #必须参数,指定被测软件的包名
    desired_cap['appPackage']='com.android.settings'
    #必须参数,指定要打开的app的页面是哪个
    desired_cap['appActivity']='.Settings'
    #不是必须的,但一般需要指定,appium封装的底层android测试工具
    desired_cap['automationName']='Uiautomator2'
    #设置app的重置策略
    desired_cap['noReset']=True
    #设置命令的超时时间
    desired_cap['NewCommandTimeout']=6000
    #用于设置中文输入
    desired_cap['unicodeKeyboard']=True
    desired_cap['resetKeyboard']=True
    
    driver=webdriver.Remote('http://localhost:4723/wd/hub', desired_cap)

    uiautomatorviewer的使用

     

    对混合app元素的识别

     下载好对应的Chromedriver的驱动 下载之后将路径添加到appium的Chromedriver Binary Path里面

    import time
    from appium import  webdriver
    desired_cap={}
    #必须参数,定义被测脚本的平台属性
    desired_cap['platformName']='Android'
    #必须参数,定义被测手机的安卓版本号(设置->关于本机->android版本,必须跟被测机对得上,不能乱写,大版本不能错,小版本可以不用写)
    desired_cap['platformVersion']='7.1.2'
    #可以写任意的值,但不能为空
    desired_cap['deviceName']='127.0.0.1:62001'
    #必须参数,指定被测软件的包名
    desired_cap['appPackage']='com.ibox.calculators'
    #必须参数,指定要打开的app的页面是哪个
    desired_cap['appActivity']='.CalculatorActivity'
    #不是必须的,但一般需要指定,appium封装的底层android测试工具
    desired_cap['automationName']='Uiautomator2'
    #设置app的重置策略
    desired_cap['noReset']=True
    #设置命令的超时时间
    desired_cap['NewCommandTimeout']=6000
    #用于设置中文输入
    desired_cap['unicodeKeyboard']=True
    desired_cap['resetKeyboard']=True
    driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_cap)
    driver.implicitly_wait(10)
    
    dic=[
        {'num1': 64,'num2': 98,'op':'+'},
        {'num1': 789,'num2': 35,'op':'-'},
        {'num1': 72,'num2': 65,'op':'*'},
        {'num1': 831,'num2': 92,'op':'/'}
    ]
    op_dic={
        '+':'plus',
        '-':'minus',
        '*':'mul',
        '/':'div'
    }
    
    for exp in dic:
        #解析第一个操作数
        for word in str(exp['num1']):
            driver.find_element('id','com.ibox.calculators:id/digit{}'.format(word)).click()
    
        #解析操作符
        driver.find_element('id','com.ibox.calculators:id/{}'.format(op_dic[exp['op']])).click()
    
        #解析第二个操作数
        for word in str(exp['num2']):
            driver.find_element('id','com.ibox.calculators:id/digit{}'.format(word)).click()
    
        #点击等于符合
        driver.find_element('id','com.ibox.calculators:id/equal').click()
    
        #定位结束框,并且读出数据
        print(driver.find_element('xpath','//android.widget.TextView[@index="1"]').text)

    高级手势操作

     

     

    TouchAction

    from appium.webdriver.common.touch_action import TouchAction

     

     

    from appium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    desired_cap={
        'platformName':'android',
        'platformVersion':'7.1.2',
        'deviceName':'127.0.0.1:62001',
        'appPackage':'com.android.settings',
        'appActivity':'.Settings',
        'automatonName':'Uiautomator2'
    }
    
    driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_cap)
    while True:
        try:
            driver.find_element('xpath','//*[@text="开发者选项"]').click()
            break
        except NoSuchElementException:
            driver.swipe(555,670,555,400,duration=1000)

     

    在app中针对日期控件的常见的处理方式:

    1.如果是第三方库,并且有公开的api接口,就可以直接使用python或者android的uiautomator这个工具直接去调用,从而设置日期的值,避免从界面上操作

    2.通过界面方式进行滑动选择操作,没有api也可以直接使用,编程和操作效率比较低

    from appium import webdriver
    
    desired_cap={
        'platformName':'android',
        'platformVersion':'7.1.2',
        'deviceName':'127.0.0.1:62001',
        'appPackage':'com.laogejizhang.account',
        'appActivity':'.MainActivity',
        'automatonName':'Uiautomator2',
        'noReset':True,
        'newCommandTimeout':6000
    }
    
    driver=webdriver.Remote('http://localhost:4723/wd/hub',desired_cap)
    driver.implicitly_wait(10)
    
    def select_data(year,month,day):
        current_year=driver.find_element('xpath','//*[@bounds="[163,783][293,817]"]').text
        current_month=driver.find_element('xpath','//*[@bounds="[]"]').text
        while True:
            if int(current_year) == int(year):
                break
            if int(current_year) > int(year):
                driver.swipe(274,740,274,800,duration=1000)
            else:
                driver.swipe(274,800,274,740,duration=1000)
        
        while True:
            if int(current_month) == int(month):
                break
            if int(current_month) > int(current_month):
                driver.swipe()
            else:
                driver.swipe()
    driver.find_element('xpath','//android.view.ViewGroup[@index="5"]/android.widget.ImageView').click()
    driver.find_element('xpath','//*[@text="信用卡"]').click()
    driver.find_element('xpath','//*[@text="广发银行"]').click()
    driver.find_element('xpath','//*[@text="请输入账单日期"]').click()
    
    select_data('2019','10','11')
    

    Appium手机操作

     

     

     

      from appium.webdriver.connectiontype import ConnectionType

     0(None)  1(Airplane Mode) 2(Wifi only) 4(Data only) 6(All networl on)

     

     

     

    展开全文
  • 本文将介绍Pefectomobilecloud在移动端自动化测试的应用。Pefecto将真实移动设备放到cloud端,并提供通过web/Eclipse插件的形式进行访问与测试。同时,Pefecto开放了基于selenium的第三方API:MobileWebDriver,支持...
  • 文章目录一、前言二、Appium 概述1、架构图UI 自动化收益环境安装桌面版本安装DOS命令安装**安装sdk**常用操作上下左右滑动点击sdk中的【uiautomatorviewer.bat】定位方式Id定位:name定位xpath定位第二种定位方式:...

    一、前言

    今天简单介绍 移动端 UI 自动测试工具 Appium。

    二、Appium 概述

    Appium 是一个自动化测试开源工具,支持 iOS 平台和 Android 平台上的原生应用,web 应用和混合应用。“移动原生应用”是指那些用 iOS SDK 或者 Android SDK 写的应用。所谓的“移动web 应用”是指使用移动浏览器访问的应用(Appium 支持 iOS 上的 Safari 和 Android 上的 Chrome)。所谓的“混合应用”是指原生代码封装网页视图——原生代码和 web 内容交互。Appium 既能在 window 安装也能在 Mac 上安装,但是 window 上只能跑安卓设备,Mac 上能跑安卓与 IOS 两个设备。

    Guihub:You can write tests with your favorite dev tools using any WebDriver-compatible language such as Java, Objective-C, JavaScript (Node), PHP, Python, Ruby, C#, Clojure, or Perl with the Selenium WebDriver API and language-specific client libraries.

    源码地址:https://github.com/appium/appium

    1、架构图

    在这里插入图片描述

    2、UI 自动化收益

    任何 UI 自动化测试都不能完部替代人工测试,收益率高不高看部门怎么使用任何工具使用都是两方看怎么使用,如果有重复的工作每次需要人工去回归,建议使用自动化去回归,部门大家都用自动使用,会让大家的心信提高因为每次都机会使用自己写的脚本去验证自己重复工作。

    脚本维护成本真的高吗?大家都说成本高,自己是否真的维护过,写过脚本?如果没有写过,没有维护过,没有发言权。只有自己用了才知道是否高。

    三、环境安装

    1、桌面版本安装

    打开下面链接选择版本为exe进行下载:

    在这里插入图片描述

    下载安装后:

    在这里插入图片描述

    点击启动:
    在这里插入图片描述

    2、DOS命令安装


    安装JDK

    下载地址:https://www.oracle.com/technetwork/java/javase/downloads/index.html

    配置环境变量:

    JAVA_HOME:

    JAVA_HOME=C:\Program Files (x86)\Java\jdk1.8.0_181
    %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
    CLASSPATH:
    .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
    

    Java 验证:

    java version "1.8.0_181"
    Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
    Java HotSpot(TM) Client VM (build 25.181-b13, mixed mode, sharing)
    

    3、安装SDK

    下载地址:

    配置环境变量:

    ANDROID_HOME
    C:\Program Files (x86)\android-sdk-windows
    Path:
    ;%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools
    
    ## 下载 node
    http://nodejs.cn/download/
    ## 安装 appium
    npm install -g appium
    
    ## 如果上面下载比较慢可以使用如下命名
    ## cnpm 安装
    npm install -g cnpm --registry=https://registry.npm.taobao.org
    cnpm install -g appium --no-cache
    cnpm i appium-doctor
    appium -v
    

    安装验证环境命令:appium-doctor

    执行命令验证是否成功:
    在这里插入图片描述

    Appium 版本检查与运行显示:
    在这里插入图片描述

    注意:如果上面环境没有配置,请自己搜索解决。

    四、常用操作方法

    • 点击:click()
    • 输入:
    sendKeys(CharSequence... keysToSend);
    
    • 清除:clear()
    • 长按:
         /**
         * 购物车商品图片
         * 长按
         * @param driver
         */
         
        public void cartSingleProductImage(AndroidDriver<AndroidElement> driver, String coordinate) {
            WaitUtil.waitWebElement(driver, getByLocator.getLocatorApp(coordinate), "长按购物车商品图片-弹出收藏与删除浮层");
            element = driver.findElement(getByLocator.getLocatorApp(coordinate));
    
            int x = element.getLocation().getX();
            int y = element.getLocation().getY();
            TouchAction action = new TouchAction(driver);
            //长按
            action.longPress(PointOption.point(x, y)).release().perform();}
    
    • 滑动:
           WebElement webElement = null;
            try {
                driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
                webElement = driver.findElementByAndroidUIAutomator(
                        "new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text(\"See more details\"))");
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    • 上下左右滑动,最简单的下滑命令行:(uuid 表示手机设备号)
    adb -s " + uuid + " shell input touchscreen swipe 400 800 400 400
    
         /**
             * 滑动方法
             *
             * @param driver
             * @param direction up、down、left、right
             */
    
            static Duration duration = Duration.ofSeconds(1);
            public static void swipe(AndroidDriver<AndroidElement> driver, String direction) {
                switch (direction.toLowerCase()) {
                    case "up":
                        SwipeUp(driver);
                        break;
                    case "down":
                        SwipeDown(driver);
                        break;
                    case "left":
                        SwipeLeft(driver);
                        break;
                    case "right":
                        SwipeRight(driver);
                        break;
                    default:
                        System.out.println("方向参数不对,只能是up、down、left、right");
                        break;
                }
            }
    
    
            /**
             * 上滑
             *
             * @param driver
             */
    
            public static void SwipeUp(AndroidDriver<AndroidElement> driver) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Dimension size = driver.manage().window().getSize();
                int height = size.height;
                int width = size.width;
                new TouchAction(driver).longPress(PointOption.point(width / 2, 100))
                        .moveTo(PointOption.point(width / 2, height - 100)).release()
                        .perform();
    
            }
    
    
            /**
             * 下滑
             *
             * @param driver
             */
    
            public static void SwipeDown(AndroidDriver<AndroidElement> driver) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Dimension size = driver.manage().window().getSize();
                int height = size.height;
                int width = size.width;
                new TouchAction(driver)
                        .longPress(PointOption.point(width / 2, height - 100))
                        .moveTo(PointOption.point(width / 2, 100)).release().perform();
            }
    
    
            /**
             * 左滑
             *
             * @param driver
             */
    
            public static void SwipeLeft(AndroidDriver<AndroidElement> driver) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Dimension size = driver.manage().window().getSize();
                int height = size.height;
                int width = size.width;
                new TouchAction(driver)
                        .longPress(PointOption.point(width - 100, height / 2))
                        .moveTo(PointOption.point(100, height / 2)).release().perform();
            }
    
    
            /**
             * 右滑
             *
             * @param driver
             */
    
            public static void SwipeRight(AndroidDriver<AndroidElement> driver) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
    
                Dimension size = driver.manage().window().getSize();
                int height = size.height;
                int width = size.width;
                new TouchAction(driver).longPress(PointOption.point(100, height / 2))
                        .moveTo(PointOption.point(width - 100, height / 2)).release()
                        .perform();
            }
    
    • 获取属性:getAttribute()
    • 获取文本:getText()
    • 获取资源:getPageSource()
    • 元素定位,两种方式。
      • 第一种使用 sdk 中的【uiautomatorviewer.bat】进行元素定位
        打开:
        在这里插入图片描述

    双击 uiautomatorviewer.bat 即可弹出:

    在这里插入图片描述

    在操作上面之前需要链接手机或者链接模拟器并操作命令显示:adb devices
    如果是模拟器需要先链接:adb connect 127.0.0.1:62001 这样再次链接.
    在这里插入图片描述

    模拟器链接显示:
    在这里插入图片描述

    点击 sdk 中的【uiautomatorviewer.bat】
    在这里插入图片描述

    链接成功显示:
    在这里插入图片描述

    鼠标点击某个控件就会提示该控件可操作的相应内容:
    在这里插入图片描述

    说明:

    其实在做移动端自动化测试,定位方式很少基本就是 id/name/xpath/ 坐标等定位方式。

    五、常见定位方式

    1、ID 定位

    在这里插入图片描述

     driver.findElement(By.id("xxxxxx")).click();
    

    2、name定位

    在这里插入图片描述

     driver.findElement(By.name("xxxxxx")).click();
    

    3、xpath 定位

    xpath定位是最常用的一种方式,可以去学习下 xpath 语法:

    但是网上也有大牛做一个插件,做 ui 自动化可直接使用:- https://github.com/lazytestteam/lazyuiautomatorviewer

    大家下载后替换 sdk 中的 uiautomatorviewer.jar 就可使用。

    点击 uiautomatorviewer.bat 再次弹出如下:

    在这里插入图片描述

    driver.findElement(By.xpath("xxxxxx")).click();
    

    4、定位 h5 页面

    启动:
    在这里插入图片描述

    点击:
    在这里插入图片描述

    再弹出对话中输入:
    在这里插入图片描述

    在下面选项框中输入:
    需要获取 appPackage 与 appActivity

    使用命令:

    aapt d badging pinduoduov4.76.0_downcc.com.apk |findstr "package launchable-activity"
    

    获取结果:
    在这里插入图片描述

    {  "platformName": "Android",  "deviceName": "127.0.0.1:62001",  "appPackage": "com.xunmeng.pinduoduo",  "appActivity": "com.xunmeng.pinduoduo.ui.activity.MainFrameActivity"}

    点击启动:

    在这里插入图片描述

    在这里插入图片描述

    显示正在启动:
    在这里插入图片描述

    启动完毕显示:
    在这里插入图片描述

    启动完毕,剩下的就是常用与其他操作一样:

    在这里插入图片描述

    六、简单 demo 示例

        import io.appium.java_client.AppiumDriver;
        import io.appium.java_client.TouchAction;
        import io.appium.java_client.android.AndroidDriver;
        import io.appium.java_client.android.AndroidElement;
        import io.appium.java_client.android.AndroidKeyCode;
        import io.appium.java_client.functions.ExpectedCondition;
        import io.appium.java_client.remote.AndroidMobileCapabilityType;
        import io.appium.java_client.remote.MobileCapabilityType;
        import io.appium.java_client.touch.LongPressOptions;
        import io.appium.java_client.touch.WaitOptions;
        import io.appium.java_client.touch.offset.PointOption;
        import org.apache.commons.io.FileUtils;
        import org.openqa.selenium.*;
        import org.openqa.selenium.remote.DesiredCapabilities;
        import org.openqa.selenium.support.ui.ExpectedConditions;
        import org.openqa.selenium.support.ui.WebDriverWait;
        import javax.imageio.ImageIO;
        import java.awt.image.BufferedImage;
        import java.io.ByteArrayInputStream;
        import java.io.File;
        import java.io.IOException;
        import java.net.MalformedURLException;
        import java.net.URL;
        import java.time.Duration;
        import java.util.ArrayList;
        import java.util.List;
        import java.util.concurrent.TimeUnit;
    
    
        /**
         * @author 7DGroup
         * @Title: Bases
         * @Description: 安装初始化类
         * @date 2019/11/20 / 22:34
         */
    
        public class DriverBase {
    
    
            public static AndroidDriver<AndroidElement> driver;
    
            /**
             * @param port :服务器启动的端口号,系统自动获取
             * @param udid :手机设备号:系统自动化获取
             * @param apk  :自动化运行的APK包,系统会根据该地址获取包名与actiber
             * @param flag :true 卸掉有重新安装与运行后自动化卸掉包。false 直接安装运行
             * @return
    
             */
    
            public static AndroidDriver<AndroidElement> initDriver(String port, String udid, String apk, boolean flag) {
                ArrayList<String> packAct = OperationalCmd.getPackAct(apk);
        //        File app = new File(".\\apk\\20171026.apk");
                DesiredCapabilities caps = new DesiredCapabilities();
                //自动安装
                if (flag) {
                    caps.setCapability(MobileCapabilityType.APP, apk);
                    //结束后会卸载程序
                    caps.setCapability(MobileCapabilityType.FULL_RESET, AndroidCapabilityType.FULL_RESET);
                }
    
                caps.setCapability(AndroidMobileCapabilityType.APPLICATION_NAME, udid);
                //PLATFORM_NAME: 平台名称
                caps.setCapability(AndroidMobileCapabilityType.PLATFORM_NAME, AndroidCapabilityType.PLATFORM_NAME);
               
               //UDID:设置操作手机的唯一标识,android手机可以通过adb devices查看
                caps.setCapability(MobileCapabilityType.DEVICE_NAME, udid);
               
               //NEW_COMMAND_TIMEOUT: appium server和脚本之间的 session超时时间
                caps.setCapability(AndroidCapabilityType.NEW_COMMAND_TIMEOUT, AndroidCapabilityType.NEW_COMMAND_TIMEOUT);
                
                //APP_PACKAG:Android应用的包名
                caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, packAct.get(0));
    
                //APP_ACTIVITY :启动app的起始activity
                caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, packAct.get(1));
    
                //UNICODE_KEYBOARD:1、中文输入不支持,2、不用它键盘会弹出来,说不定会影响下一步操作.需要注意设置后,需要将手机的输入法进行修改
                caps.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, AndroidCapabilityType.UNICODE_KEY_BOARD);
    
                //Reset_KEYBOARD:是否重置输入法
                caps.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD, AndroidCapabilityType.RESET_KEY_BOARD);
    
                //NO_SIGN:跳过检查和对应用进行 debug 签名的
                caps.setCapability(AndroidMobileCapabilityType.NO_SIGN, AndroidCapabilityType.NO_SIGN);
    
                try {
                    //appium测试服务的地址
                    String serverUrl = "http://127.0.0.1";
                    driver = new AndroidDriver<>(new URL(serverUrl + ":" + port + "/wd/hub"), caps);
    
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                }
                return driver;
            }
        }
    

    AndroidCapabilityType:

        import java.io.File;
    
        /**
         * @author 7DGroup
         * @Title: AndroidCapabilityType
         * @Description:功能配置类
         * @date 2019/11/20 / 22:01
         */
    
        public class AndroidCapabilityType {
    
            private AndroidCapabilityType() {
            }
    
            public static final boolean NO_SIGN = true;
            public static final boolean UNICODE_KEY_BOARD = true;
            public static final boolean RESET_KEY_BOARD = true;
    
            /**
             * waitElement 时的最长等待时间
             */
    
            public static final String NEW_COMMAND_TIMEOUT = "600";
            public static final String PLATFORM_NAME = "Android";
            public static final boolean FULL_RESET = true;
    
            /**
             * 向上小滑动一步
             */
    
            public static final String APP_UP_SWIPE = "adb shell input touchscreen swipe 400 800 400 300";
            public static final String APP_GET_PACK_ACTIVITY = "aapt d badging pathapk |findstr \"package launchable-activity\"";
    
            /**
             * 重启应用
             */
    
            public static final String RESTAPK = "adb -s 127.0.0.1 shell am start -n WelcomeActivityPama";
    
            /**adb*/
            /**
             * 根据包名得到进程
             */
    
            public static final String GETAPPPACKAGEPID = "adb shell ps | grep ";
    
            /**
             * 打开指定app
             */
    
            public static final String OPEN_APP = "shell am start -n packagename activity";
    
            /**
             * 本地存储截屏图片的目录,(注意配置时的格式)
             */
    
    
            public static final String LOCAL_SCREEN_FILE_URL = getpathlocal();
    
            /**
             * 获取目录工程路径
             *
             * @return
             */
    
            public static String getpathlocal() {
                File f = new File("");
                String logpath = f.getAbsolutePath() + "/test-output/html/screenshots";
                File file = new File(logpath);
                if (!file.exists()) {
                    f.mkdirs();
                }
                return file.toString();
    
            }
    
            /**
             * 本地存储截屏图片的格式
             */
    
            public static final String LOCAL_SCREEN_FILE_FORMAT = ".png";
    

    获取包名工具 getPackAct:

      /**
         * 获取包名与 APP_ACTIVITY
         *
         * @param path
         * @return
         */
        public static ArrayList<String> getPackAct(String path) {
            ArrayList<String> list = new ArrayList<>();
            try {
                List<String> execute = execute(AndroidCapabilityType.APP_GET_PACK_ACTIVITY.replace("pathapk", path), true);
                for (String s : execute) {
                    int i = s.indexOf("name='");
                    int i1 = s.indexOf("' versionCode=");
                    if (s.contains("versionCode")) {
                        String substring = s.substring(i + 6, i1);
                        list.add(substring);
                    } else {
                        int i2 = s.indexOf("'  label='");
                        String substring = s.substring(i + 6, i2);
                        list.add(substring);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return list;
        }
    

    可以使用下面做启动:

     public static AndroidDriver<?> initDriver() throws Exception {
            File app = new File(".\\apk\\20171026.apk");
            DesiredCapabilities caps = new DesiredCapabilities();
            caps.setCapability(MobileCapabilityType.DEVICE_NAME, "xxx");
            //caps.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());  //自动安装
            caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, "Appium");
            caps.setCapability(MobileCapabilityType.UDID, "127.0.0.1:62001");
            caps.setCapability(MobileCapabilityType.NEW_COMMAND_TIMEOUT, 600);
            //caps.setCapability(MobileCapabilityType.FULL_RESET, true); //结束后会卸载程序
            caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.xunmeng.pinduoduo");
            caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, "com.xunmeng.pinduoduo.ui.activity.MainFrameActivit");
            caps.setCapability(AndroidMobileCapabilityType.UNICODE_KEYBOARD, true);
            caps.setCapability(AndroidMobileCapabilityType.RESET_KEYBOARD, true);
            caps.setCapability(AndroidMobileCapabilityType.NO_SIGN, true);
            driver = new AndroidDriver<>(
                    new URL("http://127.0.0.1:4723/wd/hub"), caps);
            return driver;
    
        }
    

    测试报告:
    部分代码(如果需要请再群@)

        /**
         * @author 7DGroup
         * @Title: ReporterListener
         * @Description: 自定义报告监听类
         * @date 2019/11/21 / 18:56
         */
    
        public class ReporterListener implements IReporter, ITestListener {
            private static final Logger log = LoggerFactory.getLogger(DriverBase.class);
            private static final NumberFormat DURATION_FORMAT = new DecimalFormat("#0.000");
    
            @Override
            public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
                List<ITestResult> list = new LinkedList<>();
                Date startDate = new Date();
                Date endDate = new Date();
    
                int TOTAL = 0;
                int SUCCESS = 1;
                int FAILED = 0;
                int ERROR = 0;
                int SKIPPED = 0;
                for (ISuite suite : suites) {
                    Map<String, ISuiteResult> suiteResults = suite.getResults();
                    for (ISuiteResult suiteResult : suiteResults.values()) {
                        ITestContext testContext = suiteResult.getTestContext();
                        startDate = startDate.getTime() > testContext.getStartDate().getTime() ? testContext.getStartDate() : startDate;
                        if (endDate == null) {
                            endDate = testContext.getEndDate();
                        } else {
                            endDate = endDate.getTime() < testContext.getEndDate().getTime() ? testContext.getEndDate() : endDate;
                        }
    
                        IResultMap passedTests = testContext.getPassedTests();
                        IResultMap failedTests = testContext.getFailedTests();
                        IResultMap skippedTests = testContext.getSkippedTests();
                        IResultMap failedConfig = testContext.getFailedConfigurations();
    
                        SUCCESS += passedTests.size();
                        FAILED += failedTests.size();
                        SKIPPED += skippedTests.size();
                        ERROR += failedConfig.size();
    
                        list.addAll(this.listTestResult(passedTests));
                        list.addAll(this.listTestResult(failedTests));
                        list.addAll(this.listTestResult(skippedTests));
                        list.addAll(this.listTestResult(failedConfig));
                    }
                }
    
                /* 计算总数 */
    
                TOTAL = SUCCESS + FAILED + SKIPPED + ERROR;
    
                this.sort(list);
                Map<String, TestResultCollection> collections = this.parse(list);
                VelocityContext context = new VelocityContext();
    
                context.put("TOTAL", TOTAL);
                context.put("mobileModel", OperationalCmd.getMobileModel());
                context.put("versionName", OperationalCmd.getVersionNameInfo());
                context.put("SUCCESS", SUCCESS);
                context.put("FAILED", FAILED);
                context.put("ERROR", ERROR);
                context.put("SKIPPED", SKIPPED);
                context.put("startTime", ReporterListener.formatDate(startDate.getTime()) + "<--->" + ReporterListener.formatDate(endDate.getTime()));
                context.put("DURATION", ReporterListener.formatDuration(endDate.getTime() - startDate.getTime()));
                context.put("results", collections);
                write(context, outputDirectory);
    
            }
    
    
            /**
             * 输出模板
             *
             * @param context
             * @param outputDirectory
    
             */
    
            private void write(VelocityContext context, String outputDirectory) {
                if (!new File(outputDirectory).exists()) {
                    new File(outputDirectory).mkdirs();
                }
    
                //获取报告模板
                File f = new File("");
                String absolutePath = f.getAbsolutePath();
                String fileDir = absolutePath + "/template/";
                String reslutpath = outputDirectory + "/html/report" + ReporterListener.formateDate() + ".html";
                File outfile = new File(reslutpath);
                if (!outfile.exists()) {
                    outfile.mkdirs();
                }
    
                try {
                    //写文件
                    VelocityEngine ve = new VelocityEngine();
                    Properties p = new Properties();
                    p.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, fileDir);
                    p.setProperty(Velocity.ENCODING_DEFAULT, "utf-8");
                    p.setProperty(Velocity.INPUT_ENCODING, "utf-8");
                    ve.init(p);
    
                    Template t = ve.getTemplate("reportnew.vm");
    
                    //输出结果
                    OutputStream out = new FileOutputStream(new File(reslutpath));
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
    
                    // 转换输出
                    t.merge(context, writer);
                    writer.flush();
                    log.info("报告位置:" + reslutpath);
    
                } catch (IOException e) {
                    e.printStackTrace();
    
                }
    
            }
    
    
            /**
             * 排序规则
             *
    
             * @param list
    
             */
    
            private void sort(List<ITestResult> list) {
                Collections.sort(list, new Comparator<ITestResult>() {
                    @Override
                    public int compare(ITestResult r1, ITestResult r2) {
                        if (r1.getStatus() < r2.getStatus()) {
                            return 1;
                        } else {
                            return -1;
                        }
                    }
                });
            }
    

    模板(部分代码):

    <h2>详情</h2>
        #foreach($result in $results.entrySet())
            #set($item = $result.value)
        <table id="$result.key" class="details">
            <tr>
                <th>测试类</th>
                <td colspan="4">$result.key</td>
            </tr>
            <tr>
                <td>TOTAL: $item.totalSize</td>
                <td>SUCCESS: $item.successSize</td>
                <td>FAILED: $item.failedSize</td>
                <td>ERROR: $item.errorSize</td>
                <td>SKIPPED: $item.skippedSize</td>
            </tr>
            <tr>
                <th>Status</th>
                <th>Method</th>
                <th>Description</th>
                <th>Duration</th>
                <th>Detail</th>
            </tr>
            #foreach($testResult in $item.resultList)
                <tr>
                    #if($testResult.status==1)
                        <th class="success" style="width:5em;">success
                        </td>
                    #elseif($testResult.status==2)
                        <th class="failure" style="width:5em;">failure
                        </td>
                    #elseif($testResult.status==3)
                        <th class="skipped" style="width:5em;">skipped
                        </td>
                    #end
                    <td>$testResult.testName</td>
                    <td>${testResult.description}</td>
                    <td>${testResult.duration} seconds</td>
                    <td class="detail">
                    ##                    <a class="button" href="#popup_log_${testResult.caseName}_${testResult.testName}">log</a>
                        <button type="button" class="btn btn-primary btn-lg" data-toggle="modal"
                                data-target="#popup_log_${testResult.caseName}_${testResult.testName}">
                            log
                        </button>
                        <!-- 日志模态框 -->
                        <div class="modal fade" id="popup_log_${testResult.caseName}_${testResult.testName}" tabindex="-1"
                             role="dialog" aria-labelledby="myModalLabel_${testResult.testName}">
                            <div class="modal-dialog" role="document">
                                <div class="modal-content">
                                    <div class="modal-header">
                                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
                                                aria-hidden="true">&times;</span></button>
                                        <h4 class="modal-title" id="myModalLabel_${testResult.testName}">用例操作步骤</h4>
                                    </div>
                                    <div class="modal-body">
                                        <div style="overflow: auto">
                                            <table>
                                                <tr>
                                                    <th>日志</th>
                                                    <td>
                                                        #foreach($msg in $testResult.twooutparam)
                                                            <pre>$msg</pre>
                                                        #end
                                                    </td>
                                                </tr>
                                                #if($testResult.status==2)
                                                    <tr>
                                                        <th>异常</th>
                                                        <td>
                                                            <pre>$testResult.throwableTrace</pre>
                                                        </td>
                                                    </tr>
                                                #end
                                            </table>
                                        </div>
                                    </div>
                                    <div class="modal-footer">
                                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                    </td>
                </tr>
            #end
        </table>
        #end
    

    启动测试类:

            static AndroidDriver<AndroidElement> driver;
    
    
            /**
             * 初始化运行类
             *
             * @param udid
             * @param port
             * @throws Exception
             */
    
            @BeforeClass
            @Parameters({"udid", "port"})
            public void BeforeClass(String udid, String port) {
                Reporter.log("步骤1:启动appium与应用", true);
                LogUtil.info("---这是设备ID号-->" + udid);
                LogUtil.info("--这是运行端口--->" + port);
    
                //通过路径获取包名与APP_ACTIVITY
                String apk = "pinduoduov4.76.0_downcc.com.apk";
                driver = DriverBase.initDriver(port, udid, apk, true);
                driver.manage().timeouts().implicitlyWait(80, TimeUnit.SECONDS);
            }
    
    
            @Test
            public void T001() {
                LogUtil.info("启动");
                driver.findElement(By.id("com.xunmeng.pinduoduo:id/bo0")).click();
            }
    

    使用 xml 启动:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
    <suite name="UI自动化" parallel="tests" thread-count="1">
        <listeners>
            <listener class-name="appout.reporter.ReporterListener"></listener>
        </listeners>
        <test name="M6TGLMA721108530">
            <parameter name="udid" value="M6TGLMA721108530"/>
            <parameter name="port" value="4723"/>
            <classes>
                <class name="appout.appcase.LoginTest"/>
            </classes>
        </test>
    </suite>
    

    命令号启动:
    在这里插入图片描述

    这样跑xml就能得到如下结果。

    七、运行效果

    在这里插入图片描述

    log 弹出:

    在这里插入图片描述

    八、工程目录

    在这里插入图片描述

    注意:
    如果在启动的时候有问题,自己微调下,大概大家只是看看而已,有问题到群里问或者联系@就行会单独指导怎么使用。

    九、总结

    使用 maven 建立项目,通过 tesng 做测试类与传参,以上简单介绍了环境部署,定位方式,启动类,报告类等方法。

    主要的知识点:

    • Java
    • Testng
    • idea
    • appium
    • html

    展开全文
  • Appium是一个开源工具,用于自动化iOS收集、Android手机和Windows桌面平台的原生、混合和移动Web应用程序测试。appium是基于 webdriver 协议添加对移动设备自动化api扩展而成,基于tcp/ip协议。appium支持多平台...

    一、介绍

            Appium是一个开源工具,用于自动化iOS收集、Android手机和Windows桌面平台的原生、混合和移动Web应用程序测试。appium是基于 webdriver 协议添加对移动设备自动化api扩展而成,因此大部分的api与selenium一样 ;同时体系架构也与 selenium 一样;基于tcp/ip协议。appium支持多平台(Android、iOS等)、多语言(python、java等);Appium是跨平台的,可以用在OSX,Windows以及Linux桌面系统上运行。

    二、安装及环境配置

            提前准备好:jdk环境、Android环境;
            安装appium,下载地址:https://github.com/appium/appium-desktop/releases
            windows 版本,傻瓜式安装。

    三、连接设备

            adb devices   查询连接的设备;如果未连接,可以重启adb服务:
            adb kill -server 关闭服务; 
            adb start -server 启动服务;

            appium 连接设备: 点击搜索图标 ;三个图标分别是: start inspector session 开始检查回话、Get Raw Logs 获得原生日志、 Stop Server 停止服务

     根据连接的设备,配置连接appium的参数

            deviceName:设备名称; 值为:127.0.0.1:62001
            platformName:系统名称 ;Android or IOS
            platformVersion: 系统版本 ,指移动设备的操作系统版本,在设置里查看;   夜神模拟器查看Android版本:可在命令行窗口:adb shell getprop ro.build.version.release

            APPPackage : 应用包名,adb命令查询: pm list packages   列出所有的应用报名,pm list packages -3 指第三方; dumpsys window windows|grep -i current  ;列出当前打开的应用包名及activity  ; 查看启动的应用启动项名称:adb shell dumpsys activity top | find "ACTIVITY"
            

     前面的是包名; / 后面的是activity ,配置好,点击start session 即可链接成功。


     

     四、通过python脚本操作移动端应用

            类似于selenium 操作浏览器;导入模块 Appium-Python-Client

            初始化参数

    import time
    from appium import webdriver
    
    # 初始化参数
    desired_caps = {
        'platformName': 'Android',  # 安卓系统
        'platformVersion': '7.1.2',  # 手机安卓版本
        'deviceName': '127.0.0.1:62001',  # 设备名,
        'appPackage': 'com.taobao.taobao',  #包名 com.taobao.taobao
        'appActivity': 'com.taobao.browser.BrowserActivity',  # 启动的Activity名称
        'uuid':'127.0.0.1:62001'    #指定设备编号 ,adb devices输出结果
    }
    
    {
      "platformName": "Android",
      "platformVersion": "7.1.2",
      "deviceName": "127.0.0.1:62001",
      "appPackage": "com.taobao.taobao",
      "appActivity": "com.taobao.browser.BrowserActivity"
    }

            然后进行 appium 连接,会自动打开淘宝APP;

            操作命令:       
            我们打开Android UI分析器。获取到了目前手机页面的信息。根据我们的目的,找到需要的组件,根据组件ID就可以在上手机上定位它,从而完成我们相要的操作。

    import time
    from appium import webdriver
    
    # 初始化参数
    desired_caps = {
        'platformName': 'Android',  # 安卓系统
        'platformVersion': '7.1.2',  # 手机安卓版本
        'deviceName': '127.0.0.1:62001',  # 设备名,
        'appPackage': 'com.taobao.taobao',  #包名 com.taobao.taobao
        'appActivity': 'com.taobao.browser.BrowserActivity',  # 启动的Activity名称
        'uuid':'127.0.0.1:62001'    #指定设备编号 ,adb devices输出结果
    }
    
    
    #连接Appium Server,初始化环境,启动app ,127.0.0.1 或 localhost 地址和端口,
    #就是启动appium时界面显示的ip和端口;wd:可以理解是WebDriver的缩写;hub:是指主节点、中心节点
    driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)
    
    # 每个操作等待5秒
    driver.implicitly_wait(5)
    
    driver.find_element_by_id('XX').click()
    
    driver.find_element_by_id('XX').send_keys('芒果饼干')
    
    driver.find_element_by_id('XX').click()
    
    print("---------------")
    time.sleep(600)
    
    driver.quit()
    

            至此,一个简单的python脚本就完成了;查看手机,会发现手机正在自动做打开淘宝,搜索芒果饼干的操作;若加上断言,就是一条完整的用例。

    五、元素定位 与 操作

            两种方式:一是根据操作步骤,可以使用appium的Inspector获取登陆相关操作元素的属性;二是使用Android SDK里自带的工具uiautomatorviewer获取;
            
            元素定位常用接口
            格式:find_element_by_定位方式(value)    ,与selenium 定位一致;
            id定位:通过工具获取到按钮的 resource-id;
                    driver.find_element_by_id('resource-id')

            class定位:通过工具获取到按钮的class
                    driver.find_element_by_class_name('class')

            text定位:根据文本内容text定位;需要确认这个中文是当前页面唯一值,否则定位不到。 
                    driver.find_element_by_android_uiautomator("text('百度一下')")

            xpath定位:根据路径定位;
                    driver.find_element_by_xpath("xpath路径")

            css_selector定位(webview):只适用于webview的html页面,继承自webdriver,与pc版本的UI测试一致
                    driver.find_element_by_css_selector()

            link_text定位(webview):只适用于webview容器中的html页面,继承自webdriver,与pc版本的UI测试一致
                    driver.find_element_by_link_text()

            name定位:只适用于webview容器中的html页面,继承自webdriver,与pc版本UI测试一致。
                    driver.find_element_by_name()

            定位元素的另一种写法:find_element(by,value) ;find_element_by_方式(value)实际调用的都是find_element(by,value);要导入这个包:from selenium.webdriver.common.by import By

            如:定位id为 password 的元素
            方式一:driver.find_element_by_id("password”)
            方式二:driver.find_element(By.ID,"password")
            这种方式好处是可以直接把操作的by和value放到一个元组里,调用通用方法来传参获得元素结果。

            By的操作可以是:By.ID 相当于by_id、By.CLASS_NAME 相当于by_class_name、By.XPATH 相当于by_xpath、By.NAME 相当于by_name、By.TAG_NAME 相当于by_tag_name、By.CSS_SELECTOR 相当于by_css_selector、By.LINK_TEXT 相当于by_link_text
     

              元素操作方法:

                    找到元素后可以对元素进行的操作,如点击、输入文本等;
            click() :点击操作
            driver.find_element_by_id("su").click()

            clear():清空输入框内容
            driver.find_element_by_id("kw").clear()

            send(xx):输入框内输入内容        
            driver.find_element_by_id("com.wuba.zhuanzhuan:id/ij").send_keys("test content")

            text :获得元素的text内容
            print(driver.find_element_by_xpath(" //xxxxx").text)

            


    api参考文档:

    展开全文
  • 然后跟好朋友沟通了解到appium,然后达成协议共同学习然后我在网上找资料,一下路线就是网上一个博客中找到的:web自动化测试的路线是这样的:编程语言基础--->测试框架--->webdriver API(selenium2)--->...
  • appium 移动端自动化测试依赖jar包. appium 移动端自动化测试依赖jar包.appium 移动端自动化测试依赖jar包. appium 移动端自动化测试依赖jar包. 方便好用
  • APP移动端自动化测试框架

    千次阅读 2022-05-29 17:00:17
    APP移动端自动化基础及appium环境搭建 appium元素定位 APP自动化测试框架 框架功能: 业务功能封装、测试用例封装、测试包管理、截图出来、断言处理、日志获取、测试报告生成、测试驱动、数据配置 项目目录...
  • 移动端自动化测试(具体步骤)

    千次阅读 2020-12-21 22:00:52
    文章目录例:操作通讯录,添加人员信息,如图所示添加成功1.打开模拟器,,打开pycharm2.cmd打开黑窗口输入adb shell dumpsys window | findstr mCurrentFocus此命令3.点击androidSDK\tools下的uiautomatorviewer....
  • Appium是一个开源移动端自动化测试的框架,可用于原生,混合和移动Web应用程序测试。他使用WebDriver协议驱动iOS,Android和Windows应用程序,使用方式和selenium类似(继承) 优势 可以跨平台同时支持Android,iOS ...
  • 理想中的UI测试框架 从测试框架的角度来讲,肯定会有一些自己想要的功能或需求,对这个测试框架的期望也会很高。首先,在衡量一个测试框架的过程中,会找一些指标来衡量这个测试框架的好坏,比如说我们会要求这个...
  • Python+Pytest+Appium+Allure移动端自动化测试框架搭建1、下载安装及环境配置1.1下载安装jdk1.2下载安装Android SDK合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成...
  • 为了充分利用云测试平台维护的设备,提升空闲设备使用率,开展自动化测试替代部分回归测试、重复性测试和多设备兼容测试,同时满足如下几种类型的自动化测试需求:在多设备执行的基础上完成安装、启动、覆盖安装、...
  • Airtest移动端自动化测试环境搭建 一

    千次阅读 2020-09-28 12:07:41
    Airtest移动端自动化测试环境搭建 一 1.概述 Airtest是一个UI界面自动化测试框架,本文介绍如何搭建Airtest测试环境,并实现Android自动化测试Demo。 2.自动化项目搭建 2.1.下载AirtestIDE安装开发工具 2.1.1....
  • appium_pyton_android继承并封装了appium,Android移动端自动化测试框架。支持多设备并发运行testcase,直接错误log及截图功能,html输出测试报告等。简单介绍下用法:1、运行前请添加测试包、设备信息到config.yaml...
  • 1、本人目前在从事测试开发工作,本课程来自于实际工作经验总结。   2、课程全面、细致,对零基础童鞋和有一定经验的童鞋,都有学习价值。   3、课程全程手写代码,跟着老师学习一遍,你一定收获多多。 &...
  • 之前分享过一篇安卓UI测试,但是没有实现数据与代码分离,后期维护成本较高,所以最近抽空优化了一下。 不想看文章得可以直接去Github,欢迎拍砖 大致结构如下: testyaml管理用例,实现数据与代码分离,一个模块一...
  • Appuim移动端自动化测试,用Python语言编写的自动获取Android或iOS移动设备的信息(获取设备id号,获取设备状态,获取设备中的Android版本号,获取设备SDK版本号,获取设备品牌,获取设备型号, 获取设备ROM名)的...
  • Robot Framework移动端自动化测试----环境安装
  • 移动端自动化测试架构总结

    千次阅读 2018-05-30 17:34:52
    最近一直在做移动端测试相关的功能,整体功能基本已实现,对此我梳理了我的整体测试架构如下图:
  • appium移动端自动化测试

    千次阅读 2020-10-20 20:25:28
    appium是一款开源的,跨平台的UI自动化测试工具 适用于测试原生的或者混合型的移动APP 支持IOS,Android,Firefox OS等平台,同时该框架支持JAVA,Python,PHP等语言编写的测试脚本。 Appium与Selenium appium类库...
  • 自动化测试平台建设分享享,远程管理移动测试设备,测试开发会上分享的技术,全面,有深度、可行性、可见性;自动化测试平台建设分享享,远程管理移动测试设备,测试开发会上分享的技术,全面,有深度、可行性、可见...
  • 基于AI的移动端自动化测试框架.pdf
  • 移动端自动化测试的进化与落地.pdf
  • appium 是一个自动化测试开源工具,支持 iOS, Android, Windows, Firefox OS平台上的原生应用, 纯web应用和混合应用。 “移动原生应用”是指那些用iOS或者 Android SDK 写的应用(Application简称app)。 “移动web...
  • 基于UI的移动端自动化测试方法及系统.docx

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 33,702
精华内容 13,480
关键字:

移动端自动化测试

友情链接: DDR_CTL32.rar