当前位置: 首页 > news >正文

【测试项目】——个人博客系统自动化测试

📖 前言:本文针对个人博客项目进行测试,个人博客主要由四个页面构成:登录页、列表页、详情页和编辑页,主要功能包括:登录、编辑并发布博客、查看详情、删除博客以及注销等功能。对于个人博客的测试就是针对主要功能进行测试,然后按照页面书写测试类。


目录

  • 🕒 1. 博客系统页面概览
  • 🕒 2. 实施流程
  • 🕒 3. 编写思路
    • 🕘 3.1 添加相关依赖
    • 🕘 3.2 包结构
  • 🕒 4. 代码编写
    • 🕘 4.1 公共类AutoTestUtils
    • 🕘 4.2 BlogLoginTest(登录页测试)
    • 🕘 4.3 BlogListTest(列表页测试)
    • 🕘 4.4 BlogEditTest(编辑页测试)
    • 🕘 4.5 BlogDetailTest(详情页测试)
    • 🕘 4.6 BlogDeleteTest(博客删除测试)
    • 🕘 4.7 BlogLogoutTest
    • 🕘 4.8 runSuite(测试套件)
  • 🕒 5. 测试结果
  • 🕒 6. 小结

🕒 1. 博客系统页面概览

登录页:

在这里插入图片描述

列表页:

在这里插入图片描述

详情页:

在这里插入图片描述

编辑页:

在这里插入图片描述

🕒 2. 实施流程

自动化项目实施的基本流程:

  1. 熟悉项目
  2. 设计手工测试用例
  3. 手工测试用例转换成自动化测试用例
  4. 部署

请添加图片描述

🕒 3. 编写思路

  • 依据思维导图编写测试用例:为每个页面创建一个测试类,并在各个测试类中编写测试用例。
  • 公共属性应单独归类以便代码复用。
  • 运用测试套件以简化运行和修改过程。
  • 由于启动和现场截图功能会被频繁复用,应单独建立一个类来存放这些功能。
  • 添加隐式等待以确保页面能正确完全地加载。

🕘 3.1 添加相关依赖

创建Maven空项目后,在pom.xml里添加需要的依赖

<dependencies><!--   添加selenium依赖  --><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.24.0</version></dependency><!--   保存屏幕截图需要用到的包  --><!-- https://mvnrepository.com/artifact/commons-io/commons-io --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.16.1</version></dependency><!--   添加junit5依赖  --><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.10.2</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-params</artifactId><version>5.10.2</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-suite --><dependency><groupId>org.junit.platform</groupId><artifactId>junit-platform-suite</artifactId><version>1.11.0</version></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-engine</artifactId><version>5.10.2</version><scope>test</scope></dependency>
</dependencies>

🕘 3.2 包结构

在这里插入图片描述

🕒 4. 代码编写

🕘 4.1 公共类AutoTestUtils

功能:创建驱动、保存现场截图

注意:在保存现场截图时,应按日期对文件夹进行分类,并确保图片名称反映出测试类别的名称,以便于问题追踪。同时,要留意文件名的动态生成和时间格式的设定。

public class AutoTestUtils {public static WebDriver webDriver;@BeforeAllstatic void SetUp() {if(webDriver == null){webDriver = new ChromeDriver();}// 设置隐式等待时间为3秒webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);}public static void TearDown() {webDriver.quit();}// 保存截图的方法public static void saveScreenshot(String testName) {// 获取当前时间并格式化String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmssSSS").format(new Date());String dateFolder = new SimpleDateFormat("yyyyMMdd").format(new Date());String fileName = String.format("%s-%s.png", testName, timestamp);// 创建文件夹File folder = new File("screenshots/" + dateFolder);if (!folder.exists()) {folder.mkdirs(); // 创建文件夹}// 保存截图File screenshot = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);try {Files.copy(screenshot.toPath(), Paths.get(folder.getPath(), fileName));} catch (IOException e) {e.printStackTrace();}}
}

在这里插入图片描述

🕘 4.2 BlogLoginTest(登录页测试)

  1. 创建驱动并打开网页。
  2. 检查网页是否正常加载。
  3. 进行正常登录测试:多参数测试,使用Enter键登录。
  4. 进行异常登录测试:用户名或密码错误,以及为空的情况。
  5. 使用Order注解确保测试按正确顺序执行,避免因顺序错误导致测试失败。
  6. 确保在重新输入用户名和密码前清空之前的内容。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)public class BlogLoginTest extends AutoTestUtils {// 所有用例都需要先获取登录页面@BeforeAllstatic void baseControl() {webDriver.get("http://localhost:8080/blog_system/login.html");}/*** 检查登录页面是否正确* 右上角与左上角的显示、登录框等*/@Test@Order(1)void loginPageLoadRight() throws IOException {webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)"));webDriver.findElement(By.xpath("/html/body/div[1]/a[2]"));webDriver.findElement(By.cssSelector("body > div.login-container > form > div"));saveScreenshot(getClass().getName());}/*** 检查登录正常情况:使用多参数测试*/@Order(3)@ParameterizedTest@CsvFileSource(resources = "LoginSuccess.csv")void loginSuccess(String username, String password, String blog_list_url) throws IOException {// 在每次登录之后都要进行清空,然后才能重新输入webDriver.findElement(By.cssSelector("#username")).clear();webDriver.findElement(By.cssSelector("#password")).clear();webDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.findElement(By.cssSelector("#login-button")).sendKeys(Keys.ENTER);saveScreenshot(getClass().getName());webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 以上是登录步骤,但是并不能确保就是登录成功的// 获取到当前页面的URL,如果URL匹配则测试通过String cur_url = webDriver.getCurrentUrl();Assertions.assertEquals(blog_list_url, cur_url);// 列表页展示的用户信息是否是登录账号String cur_usr = webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3")).getText();Assertions.assertEquals(username, cur_usr);// 因为要多参数,所以在执行完一遍执行下一遍的时候需要进行页面的回退,否则找不到登录框webDriver.navigate().back();}/*** 测试完成后登录以便进行下一阶段测试*/@Order(4)@Testvoid loginSuccessAfter()  {webDriver.findElement(By.cssSelector("#login-button")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);}/*** 检查登录异常情况:使用多参数测试*/@Order(2)@ParameterizedTest@CsvSource({"admin,123", "lisi,12", "'',''"})       // 第三项为空情况void loginFail(String username, String password) throws IOException {// 在每次登录之后都要进行清空,然后才能重新输入webDriver.findElement(By.cssSelector("#username")).clear();webDriver.findElement(By.cssSelector("#password")).clear();webDriver.findElement(By.cssSelector("#username")).sendKeys(username);webDriver.findElement(By.cssSelector("#password")).sendKeys(password);webDriver.findElement(By.cssSelector("#login-button")).click();saveScreenshot(getClass().getName());webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 登录失败的检测,获取文本进行比对String expectNotNull = "为空"; // 为空字样String expectError = "错误"; // 错误字样String actual = webDriver.findElement(By.cssSelector("body")).getText();if (actual.contains(expectNotNull) ||  actual.contains(expectError)) {System.out.println("登录失败测试通过");} else {System.out.println("登录失败测试不通过");}// 导航回登录页webDriver.navigate().back();}
}

🕘 4.3 BlogListTest(列表页测试)

  1. 检验博客列表页面是否能够正常打开。
  2. 验证列表页面的“查看全文”按钮是否能正确跳转。
  3. 检查未登录时的直接链接是否会重定向到登录页面。
public class BlogListTest extends AutoTestUtils {@BeforeAllstatic void baseControl()  {webDriver.get("http://localhost:8080/blog_system/blog_list.html");}/** 博客列表页可以正常显示*/@Testvoid listPageLoadRight() throws IOException {// 可以多检查几个,确保正确webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)"));webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > img"));// 获取页面上所有博客标题对应的元素webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);int title_num = webDriver.findElements(By.cssSelector(".title")).size();// 如果元素数量不为0,则测试通过Assertions.assertNotEquals(0,title_num);saveScreenshot(getClass().getName());}
}

🕘 4.4 BlogEditTest(编辑页测试)

  1. 检验编辑页面是否能正确打开
  2. 检查博客发布是否正常:元素是否完整或部分缺失
  3. 验证“写博客”按钮的功能性
public class BlogEditTest extends AutoTestUtils {@BeforeAllstatic void baseControl()  {webDriver.get("http://localhost:8080/blog_system/blog_list.html");}/** 博客编辑页可以正常显示*/@Test@Order(1)void editPageLoadRight() throws IOException {// 找到写博客按钮,点击webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 可以多检查几个,确保正确webDriver.findElement(By.cssSelector("#submit"));webDriver.findElement(By.cssSelector("#blog-title"));saveScreenshot(getClass().getName());}/** 正确编辑并发布博客测试*/@Test@Order(2)void editAndSubmitBlog() throws IOException {// 通过JS输入标题((JavascriptExecutor) webDriver).executeScript("document.getElementById(\"blog-title\").value=\"自动化测试\"");// 编辑页的md是第三方插件,所以不可以直接使用sendKeys向编辑模块写入内容,但是可以通过点击上方按钮进行内容的插入webDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(30) > a > i")).click();webDriver.findElement(By.cssSelector("#editor > div.editormd-toolbar > div > ul > li:nth-child(5) > a > i")).click();saveScreenshot(getClass().getName());// 点击发布webDriver.findElement(By.cssSelector("#submit")).click();webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 获取当前页面的URLString cur_url = webDriver.getCurrentUrl();Assertions.assertEquals("http://localhost:8080/blog_system/blog_list.html", cur_url);saveScreenshot(getClass().getName());}
}

🕘 4.5 BlogDetailTest(详情页测试)

  1. 正确打开测试详情页:分别测试有blogId和无blogId的情况
  2. 测试删除按钮是否可用,应比较时间而非标题,因为标题可能为空
  3. 注意操作时要确保能够导航回列表页
public class BlogDetailTest extends AutoTestUtils {@BeforeAllstatic void baseControl()  {webDriver.get("http://localhost:8080/blog_system/blog_list.html");}public static Stream<Arguments> Generator() {return Stream.of(Arguments.arguments("http://localhost:8080/blog_system/blog_detail.html","博客详情页","自动化测试"));}@ParameterizedTest@MethodSource("Generator")void BlogDetail(String expected_url,String expected_title,String expected_blog_title) {// 找到第一个博客对应的查看全文按钮webDriver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/a")).click();// 获取当前页面的URL、页面title、博客标题String cur_url = webDriver.getCurrentUrl();String cur_title = webDriver.getTitle();String cur_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > h3")).getText();Assertions.assertEquals(expected_title, cur_title);Assertions.assertEquals(expected_blog_title, cur_blog_title);if (cur_url.contains(expected_url)) {System.out.println("测试通过");} else {System.out.println("测试不通过");}webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);saveScreenshot(getClass().getName());}
}

🕘 4.6 BlogDeleteTest(博客删除测试)

  1. 测试博客是否真正删除了
  2. 尝试删除别人的文章
  3. 删除完返回列表页
public class BlogDeleteTest extends AutoTestUtils {@BeforeAllstatic void baseControl()  {webDriver.get("http://localhost:8080/blog_system/blog_list.html");}@Testvoid DeleteBlog () {// 点击查看全文按钮webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();// 点击删除按钮webDriver.findElement(By.cssSelector("#delete_button")).click();// 博客列表页第一篇博客不是“自动化测试”String first_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();// 校验当前博客标题不等于“自动化测试”Assertions.assertNotEquals(first_blog_title,"自动化测试");webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);saveScreenshot(getClass().getName());// 尝试删除别人的文章// 点击查看全文按钮webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();// 点击删除按钮webDriver.findElement(By.cssSelector("#delete_button")).click();// 删除失败的检测,获取文本进行比对String expectError = "没有权限"; // 没有权限错误字样String actual = webDriver.findElement(By.cssSelector("body")).getText();if (actual.contains(expectError)) {System.out.println("删除失败测试通过");} else {System.out.println("删除失败测试不通过");}saveScreenshot(getClass().getName());webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);// 导航回列表页webDriver.navigate().back();}
}

🕘 4.7 BlogLogoutTest

  1. 测试注销后是否返回登录页
  2. 断开驱动连接
public class BlogLogoutTest extends AutoTestUtils {@BeforeAllstatic void baseControl()  {webDriver.get("http://localhost:8080/blog_system/blog_list.html");}@Testvoid Logout(){webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(6)")).click();// 校验当前页面URL是否是“http://localhost:8080/blog_system/login.html”String cur_url=webDriver.getCurrentUrl();Assertions.assertEquals("http://localhost:8080/blog_system/login.html",cur_url);// 校验提交按钮WebElement webElement = webDriver.findElement(By.cssSelector("#login-button"));Assertions.assertNotNull(webElement);webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);saveScreenshot(getClass().getName());//webDriver.quit();TearDown();}
}

🕘 4.8 runSuite(测试套件)

测试套件按照测试类的顺序执行。

@Suite
@SelectClasses({BlogLoginTest.class, BlogListTest.class, BlogEditTest.class, BlogInfoChecked.class, BlogDetailTest.class, BlogDeleteTest.class, BlogLogoutTest.class})
public class runSuite {
}

🔎 自动化测试完整源码+博客项目

🕒 5. 测试结果

实际效果(无倍速):
请添加图片描述

在这里插入图片描述

🕒 6. 小结

  1. 关注测试用例的执行顺序
  2. 检查页面元素是否存在,以确保正确性。
  3. 注意多参数测试中的页面导航问题。
  4. 多参数(多用户登录)可能导致高并发服务器错误,需交由开发处理。
  5. 登录页面测试的最后一步应为登录成功状态,以便后续测试顺利进行。
  6. 驱动关闭应在最后一个用例结束后进行。
  7. 在公共类中定义保存截图方法以保存所有用例的执行结果,便于后续查错。截图保存时使用动态时间戳,按照天或周分类保存。
  8. @SelectClasses可指定执行类的顺序。
  9. 建议获取固定元素(如时间、标题)时,使用 XPath 定位。因为 XPath 可以基于元素的层级关系和属性进行查找,所以它适合用于固定元素的定位,特别是在复杂的 DOM 结构中。
  10. 可以适当关注用例执行时间,排查是否为性能问题。
  11. 可创建单独类存放驱动释放方法,放在套件测试的最后。
  12. 测试用例数量并非越多越好。
  13. 可以使用无头模式创建驱动。

【面试题】使用Selenium 4 自动化测试工具和JUnit 5 单元测试框架结合,如何实现的,以及有什么亮点?

1)实施:
① 设计测试用例是基于个人项目的需求,通过结合Selenium 4自动化测试工具和JUnit 5单元测试框架来执行Web自动化测试(功能、步骤和技术必须明确)。
② 需要对代码中的每个包提供概要介绍(公共属性[可复用]、测试用例[基于每个页面设计]),并使用测试套件来加载所有测试类。

2)特点:
① 利用JUnit 5提供的注解,避免创建过多对象,节省资源和时间,提升自动化测试的执行效率。
只创建一次驱动对象,减少每个测试用例重复创建驱动对象,节约时间和资源。
③ 采用参数化测试,使测试用例保持简洁,提高代码可读性。
④ 通过测试套件,减少了测试人员的工作量,一次性执行所有测试用例。
⑤ 使用隐式等待机制,确保页面加载完成,提升了自动化测试的运行效率和稳定性,减少了误报的可能性。
⑥ 采用屏幕截图功能,便于问题追踪和解决。
⑦ 使用无头模式,专注于测试结果,节省屏幕空间。

编写自动化测试不难,但要提高执行速度、更有效地发现问题并避免误报才是挑战。


OK,以上就是本期知识点“个人博客系统测试”的知识啦~~ ,感谢友友们的阅读。后续还会继续更新,欢迎持续关注哟📌~
💫如果有错误❌,欢迎批评指正呀👀~让我们一起相互进步🚀
🎉如果觉得收获满满,可以点点赞👍支持一下哟~

❗ 转载请注明出处
作者:HinsCoder
博客链接:🔎 作者博客主页

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 《微信小程序实战(3) · 推广海报制作》
  • Oracle表空间管理(二)
  • Servlet入门:服务端小程序的初试(自己学习整理的资料)
  • Spring Boot实战:使用策略模式优化商品推荐系统
  • Linux的基础知识
  • Python | Leetcode Python题解之第433题最小基因变化
  • nlohmann json:读写json文件
  • seL4 Threads(四)
  • 华为HarmonyOS灵活高效的消息推送服务(Push Kit) -- 10 推送实况窗消息
  • esp32 wifi 联网后,用http 发送hello 用pc 浏览器查看网页
  • 微软宣布弃用WSUS,企业用户尽早准备替换方案
  • 内网基础知识
  • 【Python报错已解决】AttributeError: ‘WindowsPath‘ object has no attribute ‘rstrip‘
  • 如何使用Apache Kafka处理实时数据
  • 【React】(推荐项目)一个用 React 构建的 CRUD 应用程序
  • 分享的文章《人生如棋》
  • 【Leetcode】104. 二叉树的最大深度
  • Centos6.8 使用rpm安装mysql5.7
  • Codepen 每日精选(2018-3-25)
  • css属性的继承、初识值、计算值、当前值、应用值
  • GDB 调试 Mysql 实战(三)优先队列排序算法中的行记录长度统计是怎么来的(上)...
  • Idea+maven+scala构建包并在spark on yarn 运行
  • js面向对象
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • Object.assign方法不能实现深复制
  • Python学习之路13-记分
  • Shell编程
  • Terraform入门 - 3. 变更基础设施
  • yii2权限控制rbac之rule详细讲解
  • 紧急通知:《观止-微软》请在经管柜购买!
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 看域名解析域名安全对SEO的影响
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 区块链技术特点之去中心化特性
  • 突破自己的技术思维
  • 新版博客前端前瞻
  • 智能合约开发环境搭建及Hello World合约
  • 中国人寿如何基于容器搭建金融PaaS云平台
  • k8s使用glusterfs实现动态持久化存储
  • zabbix3.2监控linux磁盘IO
  • ​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化
  • ‌分布式计算技术与复杂算法优化:‌现代数据处理的基石
  • #vue3 实现前端下载excel文件模板功能
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (0)Nginx 功能特性
  • (八)Spring源码解析:Spring MVC
  • (八)光盘的挂载与解挂、挂载CentOS镜像、rpm安装软件详细学习笔记
  • (层次遍历)104. 二叉树的最大深度
  • (多级缓存)缓存同步
  • (附源码)springboot太原学院贫困生申请管理系统 毕业设计 101517
  • (南京观海微电子)——COF介绍
  • (十八)Flink CEP 详解
  • (四)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (转)程序员疫苗:代码注入
  • .NET CORE 3.1 集成JWT鉴权和授权2