目录
设计测试用例

因为测试内容过多, 我只展示功能测试, 性能测试, 界面测试,自动化测试
功能测试

文档搜索功能
搜索一个词
1> 该词是有效查询词
返回满足的所有内容: 搜索结果个数, 内容的标题, 内容截取部分, url

2> 该词不是有效查询词
结果显示框为空

搜索多个词
1> 这些词都是有效查询词
结果显示框会显示所有满足的并集内容: 搜索结果个数, 内容的标题, 内容截取部分, url


2> 有一些是有效查询词有一些不是
结果显示框只会显示有效查询词的内容: 搜索结果个数, 内容的标题, 内容截取部分, url


3> 全都是无效查询词
结果显示框不会显示任何内容

搜索暂停词
显示框不会显示任何结果

具体的逻辑
前端通过输入框输入搜索内容, 并进行点击操作,向后端发送ajax请求

后端接收请求, 然后进行查询, 最后返回给前端查询结果

最后前端接收后端的响应结果, 把结果拼接到搜索框里面

文档显示搜索结果功能
搜索的词是有效查询词

搜索的词不是有效查询词

自动化测试
测试用例设计

我们使用selenium4自动化测试工具和junit4单元测试框架结合来对文档搜索引擎的搜索功能和文档显示搜索结果功能进行自动化测试.
引入依赖
XML
<!-- 屏幕截图-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<!-- 驱动管理-->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.9.0</version>
</dependency>
<!-- selenium-->
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
功能类介绍
Utils
放置公共处理的内容: 创建驱动, 截图功能, 处理弹窗
java
package com.xioabai.doc_searcher.common;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.SessionId;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
public class Utils {
public static WebDriver driver = null;
private static SessionId sessionId;
//创建驱动对象
public static WebDriver createDriver() {
if (driver == null || sessionId == null) {
//增加浏览器配置对象,创建驱动对象的时候要强制运行访问所有的链接
ChromeOptions options = new ChromeOptions();
//表示运行所有的链接
options.addArguments("--remote-allow-origins=*");
//设置无头模式
options.addArguments("-headless");
//添加浏览器策略
// options.setPageLoadStrategy(PageLoadStrategy.NONE);//等待所有页面加载完成
//创建浏览器驱动对象,把配置放进驱动对象
driver = new ChromeDriver(options);
//添加隐式等待,全局元素等待2s
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(2));
}
return driver;
}
//统一创建驱动对象
public Utils() throws InterruptedException {
//调用driver对象
driver = createDriver();
//访问url
driver.get("http://120.26.236.46:9090/index.html");
}
//屏幕截图
public void getScreenShot(String str) throws InterruptedException, IOException {
//保存的图片路径: ./src/test/image/
// /2024-08-17/
// /test01-1743211.png
// /test02-1743222.png
// /test03-1743245.png
// /2024-08-18/
// /test01-1743222.png
// /test02-1743442.png
// /test03-1743332.png
//
// createDriver();
//屏幕截图
//设计文件日期格式
SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");//参数是年月日
SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS");//参数时分秒毫秒
//生成当前的时间
String dirTime = sim1.format(System.currentTimeMillis());
String fileTime = sim2.format(System.currentTimeMillis());
//拼接文件路径
//./src/test/image/2024-08-17/test01-17432.png
String filename = "./src/test/image/" + dirTime + "/" + str + "-" + fileTime + ".png";//方法名-时间.png
File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
//把srcFile放到指定位置
FileUtils.copyFile(srcFile, new File(filename));
}
//统一处理弹窗
public static void handleAlert() {
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(1));
wait.until(ExpectedConditions.alertIsPresent());
//处理弹窗
Alert alert = driver.switchTo().alert();
alert.accept();
}
}
TestSearchFunction
测试搜索功能
java
package com.xioabai.doc_searcher.test;
import com.xioabai.doc_searcher.common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import java.io.IOException;
public class TestSearchFunction extends Utils {
public TestSearchFunction() throws InterruptedException {
super();
}
public void searchInvalidity() throws InterruptedException, IOException {
//把页面设置最大
driver.manage().window().maximize();
//TODO 一个无效查询词
//定位搜索框
WebElement element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//输入一个无效查询词
element.sendKeys("hi");
//定位搜索按钮
element = driver.findElement(By.xpath("//*[@id=\"search-btn\"]"));
//点击搜索按钮
element.click();
//处理弹窗
handleAlert();
//通过类名来进行截图路径创建
getScreenShot(getClass().getName());
//方便看结果
// Thread.sleep(2000);
//断言搜索框为空
//定位结果显示框
element = driver.findElement(By.cssSelector("body > div > div.result > div"));
assert element.getText().equals("当前找到 0个结果!");
//TODO 有无效查询词,有有效查询词
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//清除文本框的值
element.clear();
//输入查询词
element.sendKeys("list hello");
//定位搜索按钮
element = driver.findElement(By.xpath("//*[@id=\"search-btn\"]"));
//点击搜索按钮
element.click();
//通过类名来进行截图路径创建
getScreenShot(getClass().getName());
//方便看结果
// Thread.sleep(1000);
//断言有结果
//定位结果显示框
element = driver.findElement(By.cssSelector("body > div > div.result > div:nth-child(2) > a"));
assert element.isDisplayed();
//清空文本框
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//清除文本框的值
element.clear();
}
public void searchValidity() throws InterruptedException, IOException {
//定位搜索框
WebElement element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//输入单个搜索词
element.sendKeys("array");
//定位搜索按钮
element = driver.findElement(By.cssSelector("#search-btn"));
//点击搜索按钮
element.click();
//定位结果显示框
element = driver.findElement(By.cssSelector("body > div > div.result > div:nth-child(2) > a"));
//断言有结果
assert element.isDisplayed();
//清空文本框
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//清除文本框的值
element.clear();
//定位搜索框
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//输入多个搜索词
element.sendKeys("array queue");
//定位结果显示框
element = driver.findElement(By.cssSelector("body > div > div.result > div:nth-child(2) > a"));
//断言有结果
assert element.isDisplayed();
//通过类名来进行截图路径创建
getScreenShot(getClass().getName());
driver.quit();
}
}
TestDisplayFunction
测试显示结果功能
当测试显示功能的时候,我们先测试有效词查询,然后测试无效词查询,发现测试无效词查询的时候出现了报错: 它显示的查询结果数目还是之前查询有效词的结果数目

说明第二次点击搜索按钮后,搜索结果并没有渲染完成,然后我们断言利用的对象就是之前的结果数目结果框里面的值,那么我们可以在第二次点击搜索后面加上等待,让渲染结果显示出来

最终修改代码
java
package com.xioabai.doc_searcher.test;
import com.xioabai.doc_searcher.common.Utils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import java.io.IOException;
public class TestDisplayFunction extends Utils {
public TestDisplayFunction() throws InterruptedException {
super();//直接通过父类创建驱动对象,进入访问页面
}
void testDisplay() throws InterruptedException, IOException {
//页面最大化
driver.manage().window().maximize();
//TODO 当搜索的词是有效词
//定位搜索框
WebElement element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//输入内容
element.sendKeys("array");
//定位搜索按钮
element = driver.findElement(By.cssSelector("#search-btn"));
//点击搜索框
element.click();
// Thread.sleep(1000);
//通过断言url是否显示来判断是否显示内容
element = driver.findElement(By.cssSelector("body > div > div.result > div:nth-child(2) > div.url"));
assert element.isDisplayed();
//通过类名来进行截图路径创建
getScreenShot(getClass().getName());
//清空文本框
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//清除文本框的值
element.clear();
//TODO 当搜索的词是无效词
element = driver.findElement(By.cssSelector("body > div > div.header > input[type=text]"));
//输入一个无效查询词
element.sendKeys("hello");
//定位搜索按钮
element = driver.findElement(By.xpath("//*[@id=\"search-btn\"]"));
//点击搜索按钮
element.click();
//处理弹窗
handleAlert();
//加上强制等待,等待页面渲染
Thread.sleep(1000);
//方便看结果
// Thread.sleep(2000);
//断言搜索框为空
//定位结果显示框
element = driver.findElement(By.cssSelector("body > div > div.result > div"));
// 获取元素的文本内容
String actualText = element.getText();
// 断言文本是否与预期一致
String expectedText = "当前找到 0个结果!";
assert actualText.equals(expectedText) : "Expected text '" + expectedText + "', but got '" + actualText + "'";
//通过类名来进行截图路径创建
getScreenShot(getClass().getName());
driver.quit();
}
}
我们再使用截图方法来获取结果图

最终测试套件的测试结果
全部通过, 但是测试的消耗时间有优化的空间.

性能测试

使用JMeter对文档搜索引擎进行性能测试,我们测试并发条件下搜索有效查询词的响应时间
创建梯度压测线程组 :jp@gc - Stepping Thread Group
创建http取样器

然后我们进行性能测试
查看聚合报告
我们可以看出95%的请求在3秒左右完成,最大响应时间为为21秒,说明在高并发的条件下,系统的处理请求的速度明显下降.
测试过程中发生了较少的异常情况,我们通过查看结果树来看单个接口的响应信息.
发现响应码为500,我们推测是线程数太多导致导致服务器没有处理过来

每秒处理事务数/吞吐量(TPS)
事务在测试的时候逐渐增加,吞吐量也逐渐增加,直到8秒的时候达到最大值:每秒可处理213个请求.
然后随着线程的增加吞吐量呈下降趋势,最后保持稳定状态.

响应时间
响应时间不是很稳定,随着请求数目上升,在所有线程都启动,持续运行60秒的区间达到了99%的响应时间为: 7秒左右,这个和聚合报告上面的数据是差不多的. 这说明了我们系统的性能不是很稳定, 有优化空间

生成测试报告
输入命令

生成报告

界面测试

我们此时把项目放在线上环境进行测试: Java 文档搜索
我们对搜索页面进行界面测试
初始页面
进入页面,什么都不输入
显示背景图, 输入框, 搜索按钮, 当前页面搜索结果数目, 搜索结果框为空, 我们所期待的是展示搜索框, 并且显示搜索条数最多的前十条数据.

搜索页面
搜索有效词
显示: 搜索框(里面包含搜索词),搜索按钮,显示搜索结果总数.
搜索结果框里面有搜索内容: 标蓝的标题,标红的搜索词,内容截取部分,标绿的url

搜索无效词
我们发现搜索无效词确实是不会有搜索结果,但是此时的用户体验其实不是很好,应该给个弹窗提醒用户,用户输入的词不是有效词, 应该输入正确的搜索词.

此时我们打开postman,看返回的数据,发现返回的是一个空的数组

此时我们就可以在前端加个判断条件, 判断返回的是不是一个空数组,如果是的话就弹出弹窗, 提醒用户输入有效的搜索词

把修改后的代码重新打包,部署到服务器上

最终修改结果: 成功显示输入框

总结
功能测试:
- 搜索引擎的基本功能正常运行, 正常流程可以正确执行
自动化测试:
-
测试用例50+全部通过.
-
使用了强制等待, 显示等待, 设置元素等待时间, 保证页面渲染完成, 找到正确的元素.
性能测试:
-
测试过程中, 出现了较少的异常情况, 主要达到TPS最大处理量的时候,系统不能处理更多的请求,因此返回500响应码.
-
响应时间不稳定,应该99%的响应时间在3s之内,系统性能有待提升.
界面测试:
-
搜索框, 按钮, 显示框,使用后都能够在一定时间内响应, 页面显示良好
-
异常搜索的时候, 并没有弹窗进行提醒(已解决)
-
没有搜索的时候, 主搜索框下面没有数据显示, 需求期待的是显示搜索框+显示条数最多的前十条数据.(未解决)
后续改进:
1> 对搜索结果页面进行分页处理
2> 扩大业务,能够动态对其他文档也进行处理.