20200824_小程序自动化测试与失败用例截图

1、微信小程序自动化

由于腾讯系QQ、微信是基于腾讯自研X5内核-类似webview,不是谷歌原生webview,所以调试会有些
许差异(有很多app厂商也开始采用X5内核)
微信小程序自动化测试只能够支持手机,模拟器是不行的

  • step1:打开微信小程序webview调试开关

聊天窗口输入如下URL,然后点击即打开调试开关:
http://debugmm.qq.com/?forcex5=true
http://debugx5.qq.com

  • step2:UC开发者工具识别小程序的web元素信息
  • step3:确认微信小程序对应的进程名 --com.tencent.mm:appbrand0

微信有很多的进程,我们要确定当前小程序是位于哪个进程中:

adb shell dumpsys activity top | findstr ACTIVITY 查询前台运行的所有进程

  • step4:X5内核启动参数配置
    // 支持X5内核应用自动化配置
    desiredCapabilities.setCapability("recreateChromeDriverSessions", true);
    // ChromeOptions使用来定制启动选项,因为在appium中切换context识别webview的时候,
    // 由于小程序是在一个单独的进程中,所以需要加上androidProcess:
    com.tencent.mm:appbrand0
    ChromeOptions options = new ChromeOptions();
    // 第二个参数要改成你查询到的小程序进程名
    options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand0");
    desiredCapabilities.setCapability(ChromeOptions.CAPABILITY, options);
    // 初始化会默认将chrome浏览器打开,需要将Browser置为空
    desiredCapabilities.setBrowserName("");
  • step5:一定记得加!!!不清除微信的数据
    //不清除掉微信的数据
    capabilities.setCapability("noReset",true);
  • step6:编写脚本
//微信启动需要时间,所以这里需要等待
Thread.sleep(15000);
//下拉,滑动,展示出来小程序列表
swipeDown();
androidDriver.findElementByAndroidUIAutomator("new UiSelector().text("柠檬班软件…
")").click();
//小程序加载需要时间,再等待
Thread.sleep(15000);
//切换到小程序对应的context中
androidDriver.context("WEBVIEW_com.tencent.mm:appbrand0");
//获取到所有的窗口 -- 句柄
Set<String> handles = androidDriver.getWindowHandles();
//对所有的窗口进行遍历,满足条件: 只要这个窗口包含特定的:URL/标题
for (String handle : handles) {
//否则我们就去切换handle句柄 窗口
androidDriver.switchTo().window(handle);
if(androidDriver.getTitle().equals("腾讯课堂柠檬班软件测试")){
//说明当前我们确实是在对应的窗口中
break;
}
}
//点击课程
androidDriver.findElement(By.xpath("//a[contains(text(),
'课程')]")).click();

2、微信小程序测试强调几点

  1. 真机测试
  2. 两个url点击,开启开关
  3. 进程名自己输入查看
  4. 页面下滑,选中名字,名字有可能缩写,按工具的缩写写
  5. 切换context到webview,另外小程序会打开三个页面,所以要遍历,进行窗口切换确认,什么时候用app的元素定位,什么时候用网页的元素定位,参数别搞错
  6. 微信小程序兼容的chromeDriver是V2.40,不按给出的版本选择
import com.lemon.data.Constants;
import io.appium.java_client.MobileBy;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.touch.WaitOptions;
import io.appium.java_client.touch.offset.PointOption;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Time;
import java.time.Duration;
import java.util.Set;
import java.util.concurrent.TimeUnit;


public class SmallProgramTest {
    public AndroidDriver androidDriver;
    @BeforeTest
    public void setUp() throws MalformedURLException {
        //启动微信
        DesiredCapabilities desiredCapabilities = new DesiredCapabilities();
        desiredCapabilities.setCapability("deviceName", "08e7c5997d2a");
        desiredCapabilities.setCapability("platformName","Android");
        desiredCapabilities.setCapability("appPackage","com.tencent.mm");
        desiredCapabilities.setCapability("appActivity","com.tencent.mm.ui.LauncherUI");
        //一定要注意!!!此配置一定要加 不清楚微信的数据
        desiredCapabilities.setCapability("noReset",true);
        // 支持X5内核应用自动化配置
        desiredCapabilities.setCapability("recreateChromeDriverSessions", true);
        // ChromeOptions使用来定制启动选项,因为在appium中切换context识别webview的时候,
        // 由于小程序是在一个单独的进程中,所以需要加上androidProcess: com.tencent.mm:appbrand0
        ChromeOptions options = new ChromeOptions();
        // 第二个参数要改成你查询到的小程序进程名
        options.setExperimentalOption("androidProcess", "com.tencent.mm:appbrand0");
        desiredCapabilities.setCapability(ChromeOptions.CAPABILITY, options);
        // 初始化会默认将chrome浏览器打开,需要将Browser置为空
        desiredCapabilities.setBrowserName("");

        URL url= new URL("http://127.0.0.1:4723/wd/hub");//http://127.0.0.1:4723/wd/hub
        androidDriver = new AndroidDriver(url,desiredCapabilities);
        //设置全局的隐式等待
        androidDriver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    }

    @Test
    public void testLemon() throws InterruptedException {
        //在微信的首页向下滑动进入到小程序列表
        Thread.sleep(8000);
        swipeDown(800);
        //选择对应的小程序-柠檬班软件测试
        androidDriver.findElement(MobileBy.AndroidUIAutomator("new UiSelector().text("柠檬班软件…")")).click();
        Thread.sleep(10000);
        //进入到小程序页面之后-切换context
        Set<String> contexts = androidDriver.getContextHandles();
        System.out.println(contexts);
        //切换context
        androidDriver.context("WEBVIEW_com.tencent.mm:appbrand0");
        //坑·· 小程序打开后会有三个窗口,必须要切换窗口才可以在对应的页面找元素/操作元素
        //获取打开的所有web窗口句柄
        Set<String> handles = androidDriver.getWindowHandles();
        //循环遍历集合切换正确的窗口
        for(String handle : handles){
            //条件判断:什么时候下才是正确的句柄--根据当前窗口的标题来判断
            if(androidDriver.getTitle().equals("腾讯课堂柠檬班软件测试")){
                //符合的,跳出循环
                break;
            }else{
                //切换句柄
                androidDriver.switchTo().window(handle);
            }
        }
        //坑:微信使用的是77版本webview(X5内核),不能按照常规匹配模式去找对应的chromeDriver
        //微信小程序兼容的chromeDriver是V2.40
        //定位元素
        androidDriver.findElement(By.partialLinkText("课程")).click();
        //web定位方式找元素/操作元素

    }

    //向下滑动方法
    public void swipeDown(int time){
        //获取屏幕宽和高
        int width = androidDriver.manage().window().getSize().getWidth();
        int height = androidDriver.manage().window().getSize().getHeight();
        //滑动的距离Or效果由什么决定??
        //1、由起始点和终止点的距离
        //2、滑动时间快慢
        //起始点坐标:435 610  终止点坐标:435 1206  向下滑动
        //(1)、创建touchAction对象
        TouchAction touchAction = new TouchAction(androidDriver);
        //(2)把原始坐标转换成PointOption类型的对象
        //起始点:屏幕1/2宽度  1/3高度位置
        //终止点:屏幕1/2宽度  2/3高度位置
        PointOption pointOption1 = PointOption.point(width/2,height/4);
        PointOption pointOption2 = PointOption.point(width/2,height*3/4);
        //(3)、通过touchAction完成一系列手势操作
        //先去按压起始点->移动到终止点->手指释放-->让动作生效
        //waitAction -->设置滑动的时间 WaitOptions
        Duration duration = Duration.ofMillis(time);
        WaitOptions waitOptions = WaitOptions.waitOptions(duration);
        touchAction.press(pointOption1).waitAction(waitOptions).moveTo(pointOption2).release().perform();
    }

}

3、失败用例截图

3.1 生成本地图片

public static void takeScreenshot(String filePath) {
// 类型强制转换
TakesScreenshot takesScreenshot = (TakesScreenshot) driver;
// OutputType.FILE -->返回类型为File(图片)
File srcFile = takesScreenshot.getScreenshotAs(OutputType.FILE);
// 把file(图片)保存到本地
// 给一个目标地址的File对象
File destFile = new File(filePath);
// 把原始file对象拷贝到目标地址对应的file对象中
// 第三方依赖 commons-io
try {
FileUtils.copyFile(srcFile, destFile);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

3.2 Allure报表嵌入截图

1、创建AllureReportListener类实现IHookable接口
IHookable接口作用:动态替换每一个被@Test注解标注的方法

public class TestResultListener implements IHookable {
//public int i = 1;
@Override
public void run(IHookCallBack iHookCallBack, ITestResult iTestResult) {
//在执行的时候替换掉@Test注解标注的测试方法
//System.out.println("这里是监听器的run方法");
//我们的目的是为了监听测试结果的,不是为了禁止掉测试方法执行
//让测试方法可以正常的执行
iHookCallBack.runTestMethod(iTestResult);
//监听测试的结果(失败的???) iTestResult--》保存测试的结果
if(iTestResult.getThrowable() != null){
//此时来截图
//OutputType.FILE --> 返回值类型File类型
File srcFile =
BaseTest.androidDriver.getScreenshotAs(OutputType.FILE);
//把File对象保存到本地,以图片格式
//每一次生成的截图名字都得要不一样
//System.out.println(iTestResult.get());
//如何获取到工程的根路径
String projectPath = System.getProperty("user.dir");
//时间戳
long time = System.currentTimeMillis();
//格式转换
File targetFile = new File(projectPath+"\screenshot\screenshot_"+
iTestResult.getName()+"_"+time+".png");
//i++;
try {
FileUtils.copyFile(srcFile,targetFile);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

2、配置监听器-testng.xml,和test同级别-记得要运行这文件,不然不生效

<listeners>
<listener class-name="com.lemon.listener.AllureReportListener"/>
</listeners>

 

原文地址:https://www.cnblogs.com/shishibuwan/p/13775574.html