针对博客系统的自动化测试

news2024/9/24 5:23:42

针对博客系统进行web自动化测试

文章目录

    • 针对博客系统进行web自动化测试
      • 引入依赖
      • 创建出合适的目录结构
      • AutoTestUtils
      • BlogLoginTest
      • BlogListTest
      • BLogEditTest
      • BlogDetailTest
      • 使用套件执行

关于博客系统的自动化测试的源代码已经上传至gitee

链接

引入依赖

首先在pom.xml上导入依赖

注意: 在导入依赖的时候要记得刷新一下maven,确保依赖真的下载下来了

<dependencies>
    <dependency>
        <groupId>org.seleniumhq.selenium</groupId>
        <artifactId>selenium-java</artifactId>
        <version>4.0.0</version>
    </dependency>
    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>1.4</version>
    </dependency>

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.8.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.platform</groupId>
        <artifactId>junit-platform-suite</artifactId>
        <version>1.8.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

创建出合适的目录结构

创建出文件的目录结构,在Test包下面放测试的方法,在common包下面放一些通用的方法

这样子项目结构就会很清晰明了

image-20230305141757659

AutoTestUtils

在每个测试类中可能都要创建驱动对象,频繁的创建和销毁对象,要是测试类很多的话,就很消耗资源,增加运行时间,所以最好单独创建一个方法,用来创建对象,这样子就不用频繁创建驱动对象了

由于这一块是所有的测试类都要调用的,所以单独封装出一个类,作为公用的类AutoTestUtils

//创建出驱动对象
 public static ChromeDriver createDriver() {
     //要是还没有创建出对象,就创建出一个浏览器/驱动对象
     if (chromeDriver == null) {
         chromeDriver = new ChromeDriver();
         //要是代码执行得很快,就会导致前端没渲染好,找不到元素的问题,所以要使用等待机制
         //隐式等待---最多等待10s
         chromeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
     }
     return chromeDriver;
 }

在实际的测试过程中,使用的是无头模式,根本就不会看到浏览器的页面,要是报错的话,就需要将报错的页面保存一下,方便排查问题

所以要用到屏幕截图

保存屏幕截图的时候,截图最好按照年月日 时分秒 毫秒的方式来保存,方便后面报错的时候定位错误

//设置屏幕截图的文件类型和目录类型
public List<String> getTime() {
    //使用SimpleDataFormat来进行时间转换
    SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
    SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyyMMdd");
    String fileName = simpleDateFormat1.format(System.currentTimeMillis());
    String dirName = simpleDateFormat2.format(System.currentTimeMillis());
    List<String> lists = new ArrayList<>();
    lists.add(dirName);
    lists.add(fileName);
    return lists;
}

/*
获取屏幕截图,将所有的测试用例的结果都保存下来,便于后面报错发现问题
str表示是哪个类调用了屏幕截图
 */
public void getScreenShot(String str) throws IOException {
    List<String> list = getTime();
    //希望屏幕截图保存的名称: 目录名 + 文件名(年月日 时分秒 毫秒)
    //"./src/test/java/BlogAutoTest/"
    String fileName = "./src/test/java/BlogAutoTest/" + list.get(0)+"/" + str +"_" + list.get(1)+ ".png";
    File srcFile = chromeDriver.getScreenshotAs(OutputType.FILE);
    //将屏幕截图生成的文件放到指定的文件路径下面
    FileUtils.copyFile(srcFile,new File(fileName));
}

BlogLoginTest

检查登录页面的情况的时候,主要是检查 页面能不能正常显示 页面登录成功的情况 页面登录失败的情况

package BlogAutoTest.Tests;

import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

import java.io.IOException;

//指定测试用例的执行顺序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)//手动指定测试用例的执行顺序[注解]
public class BlogLoginTest extends AutoTestUtils {
    //在测试登录页的时候,会有两个必做的步骤
    //1.创建出驱动对象   2.访问url
    //这个方法一定是是在其他的用例执行之前,就要先执行一次的,所以使用的是@BeforeAll,所以要使用static来修饰
    public static  ChromeDriver chromeDriver = createDriver();//创建驱动对象放到方法外面去,后面还要使用
    @BeforeAll
    public static  void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/login.html");
    }

    /*
    检查页面是否能正常打开
    检查点: 主页  写博客  头像
     */
    @Test
    @Order(1)
    public void  loginPageLoadSuc() throws IOException {
        chromeDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));
        chromeDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)"));
        chromeDriver.findElement(By.cssSelector("body > div.nav > img"));
        //屏幕截图,并且将类名传回去
        getScreenShot(getClass().getName());
    }

    /*
    检查页面的登陆成功的情况
     */
    //测试的不止一个账号,所以要使用参数化来进行多账号验证
    @ParameterizedTest
    @CsvSource({"zhangsan,123","lisi,123"})
    public void LoginSuc(String name, String password) throws IOException {
        //当登录别的账号的时候,就要先将之前的账号密码框清空,再进行登录
        chromeDriver.findElement(By.cssSelector("#username")).clear();
        chromeDriver.findElement(By.cssSelector("#password")).clear();

        chromeDriver.findElement(By.cssSelector("#username")).sendKeys(name);
        chromeDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        chromeDriver.findElement(By.cssSelector("body > div.login-container > form > div > div:nth-child(4) > input")).click();
        //上面的三步只是登录的基本步骤,并不能保证能登录成功,所以还要对跳转之后的页面进行检查,要是找不到元素的话就会报错
        //要是能登录成功,就一定能找到"查看全文的按钮"和"登录账号名称"
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3"));
        getScreenShot(getClass().getName());//屏幕截图,注意是:添加在返回之前,因为这里是测试了两个账号,所以会有两张截图
        //当一个账号登录成功的时候,想再登录另一个账号的时候,此时就找不到上面的3个元素了,因为此时页面已经不再是登录页面了,
        //所以要退回到登录的页面
        chromeDriver.navigate().back();
    }

    /*
    检查页面登录失败的情况
    需要注意的是:此时我们验证的是登录失败的情况,所以我们给定错误的账号或者密码,来看看错误的界面是否符合预期,要是符合预期的话,测试用例跑完之后不会报错
     */
    @ParameterizedTest
    @CsvSource({"zhangsan1,123","lisi1,123"})//测试的是登录错误的情况,所以就要使用错误的账号/密码
    @Order(2)
    public void LoginFail(String name, String password) throws IOException {
        chromeDriver.findElement(By.cssSelector("#username")).clear();
        chromeDriver.findElement(By.cssSelector("#password")).clear();

        chromeDriver.findElement(By.cssSelector("#username")).sendKeys(name);
        chromeDriver.findElement(By.cssSelector("#password")).sendKeys(password);
        chromeDriver.findElement(By.cssSelector("body > div.login-container > form > div > div:nth-child(4) > input")).click();
        //检查登录页面跳转失败的情况,结果发现,在登录成功的页面中也有这个元素,所以仅仅只有这个元素是不能判断的,可以获取一下文本
        String expectation = "用户名或者密码错误,登录失败!";
        String actual = chromeDriver.findElement(By.cssSelector("body")).getText();
        Assertions.assertEquals(expectation, actual);
        getScreenShot(getClass().getName());//屏幕截图,注意是:添加在返回之前,因为这里是测试了两个账号,所以会有两张截图
        chromeDriver.navigate().back();
    }
    //在执行完所有的测试方法之后都要将驱动对象销毁掉,所以使用的是@AfterAll,方法要由static来修饰
    //但是由于使用的是套件,所以要在最后一个测试类中销毁驱动对象,所以不能写在这里
}

BlogListTest

测试博客列表页,主要测试的就是页面是否能正常打开

package BlogAutoTest.Tests;

import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;


public class BlogListTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();

    @BeforeAll
    public static  void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_list.html");
    }

    /*
    测试列表页是否能展示出来
    检查点: 头像 查看全文按钮  文章
     */
    @Test
    public void listPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > img"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(4) > span:nth-child(1)"));
    }

}

BLogEditTest

对于测试博客编辑页,测试的有: 页面能不能正常显示出来 能不能写出并提交博客

package BlogAutoTest.Tests;

import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogEditTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();

    @BeforeAll
    public static void BaseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_edit.html");
    }
    /*
    检查博客编辑页有没有展示出来
    检查点:发布文章 文章标题
     */
    @Order(1)
    @Test
    public void editPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("#submit"));
        chromeDriver.findElement(By.cssSelector("#blog-title"));
    }

    /*
    检查博客编辑页能不能写文章并提交
     */
    @Order(2)
    @Test
    public void editSubmitBlog() {
        String expectation = "测试发布";//博客的标题
        chromeDriver.findElement(By.cssSelector("#blog-title")).sendKeys(expectation);
        //因为博客系统使用的第三方(editor.md),所以不能直接获取到输入框元素,但是可以获取到一些格式
        chromeDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(21) > a > i")).click();
        chromeDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a > i")).click();
        chromeDriver.findElement(By.cssSelector("#submit")).click();//点击提交
        String actual = chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
        //看看实际发布的博客信息与期望的博客标题是否一样
        Assertions.assertEquals(expectation, actual);
    }
    
}

BlogDetailTest

package BlogAutoTest.Tests;

import BlogAutoTest.common.AutoTestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;


public class BlogDetailTest extends AutoTestUtils {
    public static ChromeDriver chromeDriver = createDriver();

    @BeforeAll
    public static void baseControl() {
        chromeDriver.get("http://47.96.166.241:8080/blog_system/blog_detail.html?blogId=10");
    }
    /*
    测试博客详情页是否正确
    检查点:时间  账号  标题
     */
    @Test
    public void detailPageLoadSuc() {
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > div.blog-date"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3"));
        chromeDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3"));
    }
    //在套件中,当同时执行了多个类,销毁一定是最后一个步骤,所以要到处搬来搬去,永远保证最后一个执行
    @AfterAll
    public static void quit() {
        chromeDriver.quit();
    }
}

使用套件执行

想要运行以上的几个测试类,可以使用套件来指定统一运行

使用套件(suite)就能很好的管理各个测试用例的执行

package BlogAutoTest.Tests;


import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;

//使用套件来统一执行测试用例(可以手动指定类名,也可以手动指定包名,但是只会执行包中以Test或者Tests结尾的测试类)
@Suite
@SelectClasses({BlogLoginTest.class,BlogListTest.class,BlogEditTest.class,BlogDetailTest.class})
public class runSuite {

}

关于执行web自动化测试, 需要对实际场景的分析和理解,要理清楚程序的执行步骤和执行预期结果,一旦出现问题,要学会排查错误,看看到底是自己的自动化代码写错了导致误报,还是系统本身的错误

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

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

相关文章

【错误记录】映射文件发生改变

遇到映射文件发生改变在项目中有的地方是使用反射机制进行的操作&#xff0c;可能对于类进行了某些更改&#xff0c;科室映射文件没有更改&#xff0c;采用匿名就会出现这样的问题&#xff0c;解决办法要么更改映射文件&#xff0c;要不不要使用匿名调用。JavaDocs路径报红Clas…

ruoyi-vue-plus学习2(异步日志)(@EventListener)(@Async)(线程池池相关)

ruoyi-vue-plus的日志打印是通过监听器实现的&#xff0c;和原版若依稍稍不同 找到登录时记录日志的方法 该方法如下 这里的参数LogininforEvent为消息类&#xff0c;注意&#xff0c;貌似高版本的spring定义消息类不需要继承ApplicationEvent类也行。直接使用普通实体类就行…

详解-序列化和反序列化

文章目录问题使用场景序列化协议TCP/IP 4 层模型的哪一层&#xff1f;序列化协议问题 什么是序列化和反序列化? Java对象保存在文件中/网络传输Java对象&#xff0c;这些场景需要用到序列化。 序列化&#xff1a;将Java对象或数据结构转化成二进制流反序列化&#xff1a;将二…

Git简单使用

Git简单使用 git初始化操作 pwd&#xff1a;显示当前目录 git init&#xff1a;把这个目录变成git可以管理的仓库 git clone&#xff1a; 从现有 Git 仓库中拷贝项目&#xff08;类似 svn checkout&#xff09;。 克隆仓库的命令格式为&#xff1a; git clone <repo&g…

【Java基础 下】 031 -- 反射 动态代理

一、什么是反射&#xff1f; 换句话说就是&#xff08;从类里拿出来&#xff09; 可以获取到&#xff1a;&#xff08;利用反射&#xff0c;我们可以获取到类中所有的东西&#xff09; 获取是先从class字节码文件中获取的 二、获取class对象的三种方式 三种方式也对应了三种阶段…

Unity之Addressable使用注意事项

基本设置 Profile文件中配置资源构建路径和资源首次加载路径&#xff0c;资源如何设置了缓存&#xff0c;在首次加载之后会将再用缓存在缓存目录&#xff0c;后面将直接从缓存目录中读取&#xff0c;RemoteLoadPath一般要设置成可以动态修改类型的参数&#xff0c;方便项目发包…

[oeasy]python0104_指示灯_显示_LED_辉光管_霓虹灯

编码进化 回忆上次内容 x86、arm、riscv等基础架构 都是二进制的包括各种数据、指令 但是我们接触到的东西 都是屏幕显示出来的字符 计算机 显示出来的 一个个具体的字型 计算机中用来展示的字型 究竟是 如何进化的 呢&#xff1f;&#x1f914;&#x1f914; 模拟电路时…

在线客服机器人是什么?有什么用处?

在线客服机器人是客服自动智能问答 真人模拟应答以及意向分类 高效低成本可以同时进行一对多服务&#xff0c;而在一些情况下&#xff0c;在线客服机器人还可以进行客户接待&#xff0c;完全代替人工客服&#xff0c;提高整个客服中心的接待量。在这里我们拿ttkefu在线机器人为…

Spring学习——Maven进阶

分模块开发与设计 创建模块 书写模块代码 通过maven指令安装模块到本地仓库(install指令) 在pom.xml中导入坐标执行maven的install命令将模块安装到本地maven仓库 团队内部开发可以发布模块功能到团队内部可共享的仓库中&#xff08;私服) 依赖管理 依赖指当前项目运行所需…

JAVA SE:多线程

一、线程简介多任务&#xff0c;看似同时在做&#xff0c;实际上同一时间只做一件事多线程&#xff0c;相当于路上多加一条车道普通方法vs多线程&#xff1a; 程序、进程、线程&#xff1a;程序&#xff1a;静态的概念&#xff0c;程序和数据的有序集合进程&#xff1a;操作系统…

CleanMyMac X4.20最新Mac系统垃圾清理工具

CleanMyMac X是一款Mac系统垃圾清理工具,可以清除Mac系统多余的语言包、系统缓存、应用程序、PowerPc软件运行库等,是硬盘瘦身的好工具。在面对一款多功能型的软件时&#xff0c;复杂的操作面板是最容易让人头疼的&#xff0c;好在 CleanMyMac 一直以来都原生支持简体中文语言&…

python第五天作业~基础练习

目录 求十进制数字9的二进制编码&#xff1a; 求十进制数字9的二进制编码中的1的数量&#xff1a; 作业15&#xff1a;求1~100之间不能被3整除的数之和 作业16&#xff1a;给定一个正整数N,找出1到N&#xff08;含&#xff09;之间所有质数的总和 作业19&#xff1a;计算PI&…

为什么那么多人转行编程都首选Java

计算机专业通常从C语言开始学&#xff0c;非计算机专业想要转行编程首选Java的主要原因&#xff1a;市场需求量大。Java可以用于开发各种应用程序&#xff0c;包括企业级Web应用程序、移动应用程序、桌面应用程序、游戏、嵌入式系统、云基础设施等等。在游戏领域也有两大经典游…

Meta带头甩卖 VR头显打起价格战

新春三月&#xff0c;准备入手VR头显的“等等党”终于迎来降价利好。以Meta为首的一众VR厂商们纷纷打折&#xff0c;无论是为了清理库存、回收成本还是让步硬件新品&#xff0c;普通消费者都喜闻乐见。 上周五&#xff0c;Meta 率先官宣Meta Quest Pro与Meta Quest 2 的256GB版…

效率工具-快速创建虚拟机,Vagrant真香!

工欲善其事&#xff0c;必先利其器&#xff0c;开发环境和开发工具就是我们开发人员的剑&#xff0c;所以我们需要一个快并且好用的剑。本文是向大家介绍虚拟机创建vagrant&#xff0c;它能够实现开发人员本机快速创建虚拟机&#xff0c;能够带来高效学习各种技术价值。1 Vagra…

我的投稿之旅

一、铁道科学与工程学报选择这个期刊的原因是&#xff1a;感觉影响因子较低&#xff0c;而且实验室有师兄师姐中过这个期刊&#xff0c;所以抱着试一试的心态投了。投稿之前需要去官网注册账号由于方向不一致&#xff0c;被退稿了“您的稿件内容不属于本刊刊载范畴&#xff0c;…

Content-Type (MIME) el-upload文件、图片上传 | 文件改名 | 大文件 | 文件下载

MIME 为数据格式标签&#xff1b;最初 MIME 是用于电子邮件系统的&#xff0c;后来 HTTP 也采用了这一方案。 在HTTP协议消息头中&#xff0c;使用Content-Type来表示请求和响应中的媒体类型信息。 Content-Type&#xff1a;type/subtype ;parametertype 主类型&#xff0c;任…

【LeetCode每日一题】——135.分发糖果

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 贪心算法 二【题目难度】 困难 三【题目编号】 135.分发糖果 四【题目描述】 n 个孩子站成一…

【论文研读】无人机飞行模拟仿真平台设计

无人机飞行模拟仿真平台设计 摘要&#xff1a; 为提高飞行控制算法的研发效率,降低研发成本,基于数字孪生技术设计一个无人机硬件在环飞行模拟仿真平台。从几何、物理和行为3个方面研究无人机数字模型构建方法,将物理实体以数字化方式呈现。设计一种多元融合场景建模法,依据属…

Java--JMH--性能测试--测试软件运行效率/时间--StopWatch

写在前面: 很多时候想要测试代码运行时间&#xff0c;或者比较2个运行的效率。 最简单的方法就是Sytem.currentTimeMillis记录2开始和结束时间来算 但是Java 代码越执行越快&#xff0c;放在后面的方法会有优势&#xff0c;这个原因受留个眼&#xff0c;以后研究。大概有受类加…