自动化测试-终章

news2024/11/24 23:17:40

自动化测试-终章

前沿

如果想做不需要人去点击使用程序做到真正的自动化测试思想,以下是我的思想,需要跟着我的思路来,我们做一个可以测试所有页面的增删改查功能是否好使

思想一

我使用的是Java 做自动化测试,我们现做一个简单的自动化
pom 需要引入 selenium-java
然后需要搭建一下环境,需要下载 chromedriver 详情网上搜
写个测试类,以下代码就是简单的使用一下Selenium打开页面

private static final String url = "https://www.baidu.com/";
 public static void main(String[] args) {

        System.setProperty("webdriver.chrome.driver", "C:\\Program Files\\Google\\Chrome\\Application\\chromedriver.exe");
       // System.setProperty("webdriver.http.factory", "jdk-http-client");

        ChromeOptions options = new ChromeOptions();
        //options.setExperimentalOption("debuggerAddress", "127.0.0.1:9222");
        options.addArguments("--remote-allow-origins=*");
        WebDriver driver = new ChromeDriver(options);
        driver.get(url);
      }

这时候我们需要点击一个按钮,但是我们不管点击还是干什么都是需要给xpath,id,class 等,有很多的步骤就需要写很多的代码特别麻烦,那我们可不可以直接获取页面所有的xpath

 //点击新能源
    driver.findElement(By.xpath("//*[@id=\"js-typenav\"]/ul/li[1]")).click();

思想二

如何获取页面所有 xpath
就用到了新的技术 jsoup 不了解可以去百度一下
jsoup 是可以获取页面所有dom 元素
获取所有dom,如何拼接成xpath
首先创建一个类 存储dom的

package com.selenium.demo.domain;

import lombok.Data;
import org.jsoup.nodes.Element;

import java.util.List;

@Data
public class Dom {

    private String id;

    //Xpath
    private String xpath;

    //当前节点
    private Element element;

    //当前其他节点
    private List<Dom> list;

    //当前子节点
    private List<Dom> childrenList;

    //当前父节点
    private Dom parentDom;

}

如何我们去递归遍历

package com.selenium.demo.Util;

import com.selenium.demo.domain.Dom;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*
*
*
*
*
* */

public class JsoupUtil {


    /**
     * @Param WebDriver
     * @Param className  该 必须唯一 Class属性
     * @Param beginXpath 开始到该标签的Class属性
     * retrun List<Dom> 返回该标签下所有 Dom 节点
     */
    public static List<Dom> getUModalDialog(WebDriver driver, String className, String beginXpath) throws InterruptedException {
        Thread.sleep(1000);
        Document parse = Jsoup.parse(driver.getPageSource());
        //获取所有节点
        Elements uModalDialog = parse.getElementsByClass(className);
        //当前 父类 节点
        String xPath = beginXpath;
        return getAllDom(uModalDialog.get(0).children(),xPath,driver);
    }

    /**
     *
     * @param driver
     * @return 获取所有节点
     * @throws InterruptedException
     * 此方法用来刷新数据
     */
    public static List<Dom> getPushDom(WebDriver driver) throws InterruptedException {
        Thread.sleep(1000);
        String xPath = "/html/body";
        Document parse = Jsoup.parse(driver.getPageSource());
        Elements uModalDialog = parse.body().children();
        return getAllDom(uModalDialog,xPath,driver);
    }

    /**
     *
     * @param elements
     * @param xPath
     * @return List<Dom> 该节点下所有节点
     */
    public static List<Dom> getAllDom(Elements elements,String xPath,WebDriver driver){
        // 获取所有节点
        List<Dom> list = new ArrayList<>();
        // 循环所有节点
        for (Element element : elements) {
            //创建节点存放类
            Dom dom = new Dom();
            //赋值当前节点
            dom.setElement(element);
            // 赋值当前节点xpath
            getCurrentOtherXpath(elements, dom, xPath,driver);
            //赋值当前其他节点
            getCurrentOtherNodes(elements, dom, xPath,driver);
            //赋值父节点 初始无父节点
            dom.setParentDom(null);
            getElementsDoms(dom,driver);
            list.add(dom);
        }
        return list;
    }

    /**
     * @Param Dom 父节点
     * */
    public static void getElementsDoms(Dom dom,WebDriver driver){
        if(dom.getElement().children().size() > 0){
            //获取当前所有节点
            List<Dom> doms = listDom(dom.getElement().children(),dom.getXpath(),driver);
            //获取了子节点的Dom
            dom.setChildrenList(doms);
            for (Dom childrens : doms) {
                childrens.setParentDom(dom);
                getElementsDoms(childrens,driver);
            }
        }else{
            //获取当前所有节点
            List<Dom> doms = listDom(dom.getElement().children(),dom.getXpath(),driver);
            //获取了子节点的Dom
            dom.setChildrenList(doms);
        }
    }





    //获取当前节点 xpath
    public static void getCurrentOtherXpath(Elements elements, Dom dom, String xPath,WebDriver driver){
        //获取当前所有节点
        List<Dom> doms = listDom(elements,xPath,driver);
        for (Dom haveXpathDom : doms) {
            if(haveXpathDom.getElement() == dom.getElement()){
                dom.setXpath(haveXpathDom.getXpath());

            }
        }
    }

    //@Param 当前节点
    //@Param 当前Dom
    public static void getCurrentOtherNodes(Elements elements,Dom dom,String xPath,WebDriver driver){
        //获取当前其他所有节点
        List<Dom> doms = listDom(elements,xPath,driver);
        for (int i = 0 ; i < doms.size() ; i++) {
            Dom haveXpathDom = doms.get(i);
            if(haveXpathDom.getElement() == dom.getElement()){
                doms.remove(i);
            }
        }
        dom.setList(doms);
    }

    // 获取当前所有节点
    public static List<Dom> listDom(Elements elements, String xPath,WebDriver driver){
        //当前节点用了几个
        Map<String , Integer> useDomSubscript = getDomMax(elements);

        List<Dom> list = new ArrayList<>();
        for (Element element : elements) {
            Dom dom = new Dom();
            String tagName = element.tagName();

            //如果 存在 当前节点超过2个 赋值Xpath
            if(useDomSubscript.containsKey(tagName)){
                dom.setXpath(xPath+"/"+tagName+"["+useDomSubscript.get(tagName)+"]");
                useDomSubscript.put(tagName,useDomSubscript.get(tagName)+1);
            }else{
                dom.setXpath(xPath+"/"+tagName);
            }
            //赋值当前 element
            dom.setElement(element);
            list.add(dom);
        }
        return list;
    }


    public static void setXpathId(WebDriver driver, String xPath,String id){
        WebElement webElement = driver.findElement(new By.ByXPath(xPath));
        JavascriptExecutor js = (JavascriptExecutor) driver;
        js.executeScript("arguments[0].setAttribute(arguments[1],arguments[2])",webElement, "id", id);
    }


    //获取超出2个以上的节点
    public static Map<String , Integer> getDomMax(Elements elements){
        Map<String , Integer> useDomSubscript = new HashMap<>();

        Map<String, Integer> domSubscript = getDomSubscript(elements);

        for (Map.Entry<String,Integer> entry : domSubscript.entrySet()) {
            //当前节点超过2个
            if(entry.getValue() > 1){
                useDomSubscript.put(entry.getKey(),1);
            }
        }
        return useDomSubscript;
    }

    //获取所有相同节点数量
    public static Map<String , Integer> getDomSubscript(Elements elements){
        Map<String , Integer> map = new HashMap();
        for (Element domSubscript : elements) {
            //存在 数量+1
            if(map.containsKey(domSubscript.tagName())){
                map.put(domSubscript.tagName(),map.get(domSubscript.tagName())+1);
            }else{
                //不存在 默认1
                map.put(domSubscript.tagName(),1);
            }
        }
        return map;
    }
}

getPushDom 调用 getPushDom 就会获取到所有的dom节点的xpath了

思想三

比如我想做一个对后台管理增加做一个表单检查
在这里插入图片描述
调用到getPushDom 获取到所有dom再去递归,先获取到组件表单找到class=“el-form”
在这里插入图片描述
然后获取class=“el-form-item” 是不是就获取到了所有输入框
进行逻辑检查比如是否禁用 disabled=“disabled”
在这里插入图片描述
那我们怎么找到想要的输入框
可以根据label 在找
在这里插入图片描述
以上就是大概的思路
如果自己封装组件可以自己封装class id 等其他规范一些
我已经开发到可以检查普通的crud的页面了
还有许多的问题要解决
比如复杂的需要怎么办
1.可以先从需求文档下手,先提交需求文档,然后代码读取需求文档
根据需求文档进行每一步的操作.反正真正的开发也要写需求文档,
写完是不是就省下了测试,让程序帮你.
2.页面dom是动态的怎么办
就是可能其中一个隐藏的input,点击一个按钮才出来,这时候我们获取的dom是死数据不刷新,所以我们要仿照前端的动态刷新方法,每一步的操作我们都要重新获取页面元素
3.程序运行的慢怎么办
我觉得慢没啥问题,让程序全自动跑放后台挂着呗,而且可以一下跑多个用例,10几个用例一起跑,不比你人去一个一个用例去点快

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/600719.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt中的窗口类及其特点

目录 常用的窗口类 窗口的显示内嵌窗口 QWidget内嵌窗口演示 QWidget不内嵌窗口演示 QDialog类型的窗口特点 QMainWindows窗口的特点 总结 常用的窗口类 常用的窗口类有 3 个 在创建 Qt 窗口的时候&#xff0c;需要让自己的窗口类继承上述三个窗口类的其中一个QWidget 所有…

增量数据抽取技术

写在前面 本文隶属于专栏《大数据从 0 到 1》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和文献引用请见《大数据从 0 到 1》 正文 在数据仓库中要实现增量抽取&#x…

STL-string-1

stoi int stoi (const string& str, size_t* idx 0, int base 10);int stoi (const wstring& str, size_t* idx 0, int base 10); Convert string to integer 解析str&#xff0c;将其内容解释为指定基数的整数&#xff0c;该整数作为int值返回。 如果idx不是空…

QLoRa:在消费级GPU上微调大型语言模型

大多数大型语言模型(LLM)都无法在消费者硬件上进行微调。例如&#xff0c;650亿个参数模型需要超过780 Gb的GPU内存。这相当于10个A100 80gb的gpu。就算我们使用云服务器&#xff0c;花费的开销也不是所有人都能够承担的。 而QLoRa (Dettmers et al.&#xff0c; 2023)&#x…

公司裁员不给赔偿怎么办?

阅读本文大概需要 1.61 分钟。 最近在星球回答球友问题的时候&#xff0c;发现不少人都提到裁员这个话题。 有球友说他们公司在裁员&#xff0c;但不想给赔偿。 领导给他的方案是把年假调休休了&#xff0c;然后再给三周找工作时间&#xff0c;这三周不用打卡&#xff0c;三周后…

茅塞顿开的C#代码——通用型科学计算器

计算器是经常遇到的编程作业。 一般都是实现加、减、乘、除四则运算的普通计算器。 这里介绍用几十行C#代码实现的复杂的《科学计算器》&#xff0c;可以计算各种函数。 不知道其他语言实现同样的功能需要编写多少行代码&#xff1f;20000行&#xff1f; using System; usin…

SpringBoot接口如何正确地接收时间参数

唠嗑部分 在做Java开发时&#xff0c;肯定会碰到传递时间参数的情况吧&#xff0c;比如用户的出生日期、活动的开始&#xff0c;结束日期等等&#xff0c;这些参数往往是由前端传递过来的&#xff0c;那么在SpringBoot项目中&#xff0c;该如何正确的接收日期参数呢&#xff0…

如果不小心上了电信黑名单,应该怎么妥善处理呢?

有些小伙伴们在处理不用的手机卡时&#xff0c;可能会粗心大意&#xff0c;认为不用了就用不了呗&#xff0c;存在欠费停机的情况下也没有及时的去补交欠费&#xff0c;然后销户&#xff0c;导致了自己不小心上了电信黑名单&#xff0c;那遇到这种情况&#xff0c;应该怎么妥善…

论文解读 | 利用图形卷积核在距离图像中实现高效的3D目标检测

原创 | 文 BFT机器人 01 摘要 该论文提出了一种基于范围图像的高效3D物体检测方法&#xff0c;通过利用图卷积核来提取每个像素周围的局部几何信息。 作者设计了一种新颖的2D卷积网络架构&#xff0c;并提出了四种替代内积核心的卷积核&#xff0c;以注入所需的三维信息。该方法…

GPT最常用的应用场景有哪些?

生成式预训练转换器&#xff08;GPT&#xff09;是一种深度学习模型&#xff0c;它能够根据给定的提示生成类似人类的文本&#xff0c;彻底改变了自然语言处理&#xff08;NLP&#xff09;领域。 聊天机器人和虚拟助手 GPT最受欢迎的应用程序之一是开发聊天机器人和虚拟助手。凭…

【Python 自然语言处理(NLP)】零基础也能轻松掌握的学习路线与参考资料

Python 自然语言处理&#xff08;NLP&#xff09;是目前人工智能&#xff08;AI&#xff09;发展中的重要领域。随着科技的不断进步&#xff0c;NLP已经被应用于文本自动摘要、机器翻译、语音识别、情感分析、问答系统等各项实际任务中。 要学习 Python 自然语言处理&#xff…

“河南省数字化转型与信息技术应用创新专家研讨会-政府数字化转型推动信创产业发展”专场活动成功召开

由《中国信息化》杂志社主办的“2023河南省数字化转型与信息技术应用创新专家研讨会——政府数字化转型推动信创产业发展”专场活动于5月27日&#xff0c;在郑州成功举办。本次活动由深圳竹云科技股份有限公司协办&#xff0c;由河南省测绘学会、中国信息主管平台支持。中国交通…

Windows 安装部署 MinIo

1、下载地址 安装包下载地址&#xff1a;https://min.io/download#/windows 2、安装目录 下载的是一个可执行文件 minio.exe 将其放到一个方便寻找的目录&#xff0c;我这里放在 D:\develop\minio 同时新建一个 data 文件夹&#xff0c;用来存储上传的文件 3、启动 MinIo 服…

Godot引擎 4.0 文档 - 第一个 3D 游戏

本文为Google Translate英译中结果&#xff0c;DrGraph在此基础上加了一些校正。英文原版页面&#xff1a; Your first 3D game — Godot Engine (stable) documentation in English 你的第一个 3D 游戏 在这个循序渐进的教程系列中&#xff0c;您将使用 Godot 创建您的第一…

Java程序设计入门教程 -- 二维数组

二维数组创建 定义数组 声明二维数组 Java中二维数组的声明格式&#xff1a; 数据类型名[ ][ ] 数组名; 或 数据类型名 数组名[ ][ ]; 分配数组内存 常用格式&#xff1a; new 数组名[ M][N ] ; //M&#xff0c;N为数组行号和列号 分配数组内存 1&#xff09;规…

chatgpt赋能python:Python的几次方符号介绍

Python的几次方符号介绍 当我们在使用Python编程时&#xff0c;经常需要进行数学计算。其中最常见的计算就是幂运算。Python使用幂运算符号来表示一个数的几次方。这个符号既可以用在数字之间&#xff0c;也可以用在变量之间。在本文中&#xff0c;我们将介绍Python中的几次方…

堆基础1_小白垃圾笔记

小白垃圾笔记&#xff0c;不建议阅读。 目录 1.什么是堆&#xff1f; 2.堆从哪里来&#xff1f; 3.堆管理器是什么 4.堆申请的实现方式 1.brk&#xff1a;brk仅仅主线程申请小空间的时候用&#xff0c;子线程不可调用brk。 2.mmap&#xff1a;主线程申请大的内存的时候和…

Mysql小知识 delete 清空表之后,磁盘空间未发生变化?

1. 删除空洞 1.1 案例展示 首先我们先来看这样一个例子。 我现在有一个名为 sakila 的数据库&#xff0c;该库中有一个 film 表&#xff0c;这个表中有 1000 条记录&#xff0c;我么先来看下这 1000 条记录占用了多少存储空间&#xff1a; 小伙伴们可以看到&#xff0c;这个…

Go-FastDFS 本地对象存储,Windows环境搭建(下载安装教程)!

文章目录 Go-FastDFS简介与地址下载安装服务与管理端台可视化测试 Go-FastDFS简介与地址 go-fastdfs 是一个基于 http 协议的分布式文件系统&#xff01; 它基于大道至简的设计理念&#xff0c;一切从简设计&#xff0c;使得它的运维及扩展变得更加简单&#xff0c;它具有高性…

Elasticsearch:使用带有 X-Opaque-Id 的慢速查询功能在 Elasticsearch 中调试慢速查询

如果你在软件堆栈中使用 Elasticsearch&#xff0c;你可能已经意识到 Elasticsearch 管理大量数据和提供实时搜索功能的强大能力。 了解 Elasticsearch 中的慢速查询 Slow Log 是 Elasticsearch 的内置功能&#xff0c;可用于识别慢速搜索。 任何花费时间超过预期的请求都会记…