自动化测试-终章
前沿
如果想做不需要人去点击使用程序做到真正的自动化测试思想,以下是我的思想,需要跟着我的思路来,我们做一个可以测试所有页面的增删改查功能是否好使
思想一
我使用的是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几个用例一起跑,不比你人去一个一个用例去点快