作者简介: zoro-1,目前大三,正在学习Java,数据结构等
作者主页: zoro-1的主页
欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖
项目简介
一. 项目背景
在数字化时代,音乐已深深融入人们的日常生活,其消费和传播方式也发生了显著转变。传统音乐播放方式逐渐向线上转变,越来越多的人希望能够通过方便的网络平台,在任何时间和地点享受丰富多样的音乐资源。为了满足这一需求,我们研发了一个在线音乐播放器项目,目标是为用户提供一个功能强大且易于操作的音乐播放和管理平台。用户将不再局限于本地音乐的存储,能够轻松地探索、播放和管理海量的音乐曲目。
二. 运用技术
(1)后端开发
- Spring 框架:作为核心框架,Spring 提供依赖注入等功能,有效管理组件对象,解耦模块之间的依赖关系,提高代码的可维护性和扩展性。
- SpringBoot:基于 Spring,SpringBoot 简化了项目的搭建和配置,通过自动配置让开发者专注于业务逻辑,显著提升开发效率,并便于项目的部署和运维。
- Mybatis:作为数据访问层的核心,Mybatis 灵活地将 SQL 查询与 Java 代码映射,便于对 MySQL 数据库进行数据持久化,满足高效的数据访问需求。
- SpringMVC:遵循 MVC 设计模式,SpringMVC 清晰分离前端请求与后端处理,负责处理各种 HTTP 请求,如用户登录和音乐查询,并将结果返回前端展示。
- BCrypt 加密算法:BCrypt 用于加密存储用户密码,确保数据库中的密码安全,有效防止泄露导致的账号安全问题。
(2)前端开发
- HTML:构建页面的基本结构,定义各个元素与布局,如音乐列表、用户登录和喜欢音乐列表等页面的框架。
- CSS:用于美化页面样式,通过设置字体、颜色、背景和布局等属性,提升页面的视觉效果和用户体验。
- JS:为页面添加动态交互功能,实现音乐播放控制、用户操作响应(如登录按钮点击、添加喜欢音乐)和数据验证,增强页面的交互性。
- jQuery:简化 JavaScript 开发,提供丰富插件和简便操作方法,便于选择页面元素、绑定事件和实现动画效果,提高前端开发效率与代码简洁性。
- Ajax:实现前端与后端的异步数据交互,允许在不刷新页面的情况下与服务器传输数据,如实时查询音乐和更新播放列表,提升用户体验的流畅性。
(3)数据库
采用 MySQL 关系型数据库存储数据,能够高效管理音乐信息(如歌曲名、歌手、音频文件路径)、用户信息(用户名、密码)和用户音乐喜好(喜欢的歌曲),确保数据的完整性、一致性与持久性,为平台的稳定运行提供有力支持。
三.项目功能
- 登录功能:用户通过已存在的用户名和加密后的密码登录,成功后跳转到音乐列表页。
- 音乐列表页:展示所有音乐信息,包括音乐名称和歌手。每个音乐行有播放、暂停、删除、喜欢三个功能按钮,并提供多选框以支持批量删除操作。
- 喜欢音乐列表页:布局与音乐列表页相似,提供取消喜欢音乐和返回首页的功能,支持对喜欢的音乐进行查询,但不支持批量删除。
- 上传音乐功能:用户在音乐列表页上传音乐,可输入歌手名。
四.功能测试
1.编写测试用例
2.具体功能测试
(1)正常登录(账号密码正常)
(2)错误登录(密码错误)
(3)删除单个音乐
(4)批量删除音乐
(5)喜欢音乐
(6)上传音乐
(7)错误上传
(8)查询音乐
(9)取消收藏音乐
3.发现bug以及解决bug
(1)bug 1 ——密码错误状态下也可以正常登录
问题说明:这里我输入的密码是12345而数据库正密码是123456这里点击登录仍然可以正常登录,显然不符合需求。
解决问题:经过查看代码我发现是登录的接口逻辑出现错误,这里密码匹配不管有用吗成功返回的语句都是成功,显然是我复制是忘记更改返回值中的status和message值了应该为 return new ResponMessage<>(-1, “⽤⼾名或者密码错误”, userinfo);
修改bug后
(2)bug 2 ——上传文件为以ogg后缀的Word文件也可以上传
问题说明:上传文件需求的文件是以ogg为后缀的音频文件,这里可以上传以ogg后缀的Word文件,显然是不符合需求的。
解决问题:经过思考,发现是没有添加对ogg文件格式的筛选,只筛选了后缀名为ogg的。只能判断这个文件是否是以ogg为后缀名,不能判断这个文件是否真是ogg音频文件,所以我加了一个对ogg文件格式判断的函数 。
public static boolean isOggFileByHeader(String filePath) {File file = new File(filePath);if (!file.exists() || file.isDirectory()) {return false;}try (FileInputStream fis = new FileInputStream(file)) {byte[] buffer = new byte[OGG_HEADER.length];int bytesRead = fis.read(buffer);if (bytesRead == OGG_HEADER.length) {for (int i = 0; i < OGG_HEADER.length; i++) {if (buffer[i] != OGG_HEADER[i]) {return false;}}return true;}} catch (IOException e) {e.printStackTrace();}return false;}
修改bug后
五.自动化测试
1.编写测试化用例
2.自动化测试代码编写
(1)创建空项目
① 添加依赖(pom.xml 文件)代码如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>music_selenium</artifactId><version>1.0-SNAPSHOT</version><dependencies><dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>4.0.0</version></dependency><dependency><groupId>io.github.bonigarcia</groupId><artifactId>webdrivermanager</artifactId><version>5.8.0</version><scope>test</scope></dependency><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.6</version></dependency></dependencies><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties></project>
② 创建项目结构,如下图所示:
(2)创建测试用例工具类
创建 Utils 类,用它存放我们自动化代码中通用的方法,在这个类中我们要创建的方法如下:
- 创建驱动对象;
- 创建屏幕截图方法;
- 创建构造方法。
有关 Utils 类的具体代码及详细介绍如下所示:
package common;import io.github.bonigarcia.wdm.WebDriverManager;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;public class Utils {public static WebDriver driver;public static WebDriver createDriver(){if(driver == null){WebDriverManager.chromedriver().setup();ChromeOptions options = new ChromeOptions();//允许访问所有的链接options.addArguments("--remote-allow-origins=*");driver = new ChromeDriver(options);//等待driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(1));}return driver;}public Utils(String url){//调用driver对象driver = createDriver();//访问urldriver.get(url);}public void getScreenShot(String str) throws IOException {// ./src/test/image/// /2024-07-17/// /test01-17453010.png// /test02-17453020.png// /2024-07-18/// /test01-17453030.png// /test02-17453034.png//屏幕截图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-07-17/test01-17453020.pngsrc/testString filename ="./src/test/image/"+ dirTime +"/" + str + "-" + fileTime+".png";File srcFile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE);//srcFile放到指定位置FileUtils.copyFile(srcFile,new File(filename));}
}
(3)创建登录测试用例类
创建 Login 类,在这里编写登录页面的所有测试用例,在这里我们要完成的事情如下:
- 检查登录页面是否正确加载;
- 检查正常登录功能是否正常;
- 检查异常登录功能是否正常。
有关 Login 类的具体代码及详细介绍如下所示:
package 界面测试;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.NoAlertPresentException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;import java.io.IOException;
import java.time.Duration;public class Login extends Utils {static String url="http://127.1.0.0:8080/login.html";public Login(String url) {super(url);}void login() throws InterruptedException, IOException {createDriver();// 显式等待机制,等待元素可操作WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(1));// 输入用户名WebElement usernameField = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#user")));usernameField.clear();usernameField.sendKeys("lisi");// 输入密码WebElement passwordField = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#password")));passwordField.clear();passwordField.sendKeys("123456");// 点击登录按钮WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#login-form > button")));loginButton.click();// 处理完警告框后再进行截图操作try {// 处理警告框Alert alert = wait.until(ExpectedConditions.alertIsPresent());alert.accept();} catch (NoAlertPresentException e) {// 没有警告框,继续执行}getScreenShot("login");}void false_login() throws InterruptedException, IOException {createDriver();// 显式等待机制,等待元素可操作WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(3));// 输入用户名WebElement usernameField = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#user")));usernameField.clear();usernameField.sendKeys("lisi");// 输入密码WebElement passwordField = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#password")));passwordField.clear();passwordField.sendKeys("12345");// 点击登录按钮WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(By.cssSelector("#login-form > button")));loginButton.click();try {// 处理警告框Alert alert = wait.until(ExpectedConditions.alertIsPresent());alert.accept();} catch (NoAlertPresentException e) {// 没有警告框,继续执行}// 处理完警告框后再进行截图操作getScreenShot("false_login");}}
(4)创建音乐列表测试用例类
创建 Music_List 类,在这里编写列表页面的所有测试用例,在这里我们要完成的事情如下
- 检查列表页面是否能正确加载;
- 检查音乐的查询功能是否正常;
- 检查音乐的删除功能是否正常;
- 检查选中音乐的删除功能是否正常;
- 检查喜欢音乐的功能是否正常。
有关 Music_List 类的具体代码及详细介绍如下所示:
package 界面测试;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class Music_List extends Utils {public Music_List(String url) {super(url);}//搜索测试void search() throws IOException {driver.findElement(By.cssSelector("#musicSearch")).sendKeys("不");driver.findElement(By.cssSelector("#searchArea > button.btn.btn-primary")).click();getScreenShot("search");driver.findElement(By.cssSelector("#musicSearch")).clear();driver.findElement(By.cssSelector("#musicSearch")).sendKeys("唠赵头儿 - 不说");driver.findElement(By.cssSelector("#searchArea > button.btn.btn-primary")).click();getScreenShot("search");//重置driver.findElement(By.cssSelector("#searchArea > button.btn.btn-secondary")).click();}//测试界面是否正常出现void list() throws IOException {driver.getTitle().equals("我的音乐");getScreenShot("list");}//喜欢测试void love() throws IOException, InterruptedException {driver.findElement(By.cssSelector("#info > tr:nth-child(1) > td.operation-buttons > button:nth-child(2)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.getText().equals("喜欢成功!");alert.accept();getScreenShot("love");}//上传测试void upload() throws InterruptedException {String text=driver.findElement(By.cssSelector("#searchResults")).getText();Pattern pattern = Pattern.compile("\\d+");Matcher matcher = pattern.matcher(text);driver.findElement(By.cssSelector("#uploadArea > form > input[type=text]:nth-child(2)")).sendKeys("***");driver.findElement(By.cssSelector("#uploadArea > form > input[type=file]:nth-child(1)")).sendKeys("C:\\Users\\lenovo\\鱼化龙飞 - 《爱错》_mp3.ogg");driver.findElement(By.cssSelector("#uploadArea > form > input[type=submit]:nth-child(3)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.accept();String text1=driver.findElement(By.cssSelector("#searchResults")).getText();Matcher matcher1 = pattern.matcher(text1);int i = 0,i1=0;if (matcher.find()) {i = Integer.parseInt(matcher.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i);}if (matcher1.find()) {i1 = Integer.parseInt(matcher1.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i1);}if(i==i1-1){System.out.println("上传成功");}}//删除测试void delete() throws IOException, InterruptedException {String text=driver.findElement(By.cssSelector("#searchResults")).getText();Pattern pattern = Pattern.compile("\\d+");Matcher matcher = pattern.matcher(text);driver.findElement(By.cssSelector("#info > tr:nth-child(2) > td.operation-buttons > button:nth-child(1)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.accept();Thread.sleep(1000);Alert alert1=driver.switchTo().alert();alert1.accept();String text1=driver.findElement(By.cssSelector("#searchResults")).getText();Matcher matcher1 = pattern.matcher(text1);int i = 0,i1=0;if (matcher.find()) {i = Integer.parseInt(matcher.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i);}if (matcher1.find()) {i1 = Integer.parseInt(matcher1.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i1);}if(i==i1+1){System.out.println("删除成功");}getScreenShot("delete");}void delete_sel() throws InterruptedException {String text=driver.findElement(By.cssSelector("#searchResults")).getText();Pattern pattern = Pattern.compile("\\d+");Matcher matcher = pattern.matcher(text);driver.findElement(By.cssSelector("#\\38 2")).click();driver.findElement(By.cssSelector("#\\37 9")).click();driver.findElement(By.cssSelector("#searchArea > button:nth-child(4)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.accept();Thread.sleep(1000);Alert alert1=driver.switchTo().alert();alert1.accept();String text1=driver.findElement(By.cssSelector("#searchResults")).getText();Matcher matcher1 = pattern.matcher(text1);int i = 0,i1=0;if (matcher.find()) {i = Integer.parseInt(matcher.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i);}if (matcher1.find()) {i1 = Integer.parseInt(matcher1.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i1);}if(i==i1+2){System.out.println("删除成功");}}}
(5)创建喜欢列表测试用例类
创建 Music_Love 类,在这里编写喜欢列表页面的所有测试用例,在这里我们要完成的事情如下:
- 检查喜欢列表页面是否能正确加载;
- 检查喜欢音乐的查询功能是否正常;
- 检查取消喜欢音乐的功能是否正常;
- 检查回到大厅的按钮功能是否正常。
package 界面测试;import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;public class Music_Love extends Utils {public Music_Love(String url) {super(url);}//测试界面是否显示成功void lovemusic(){driver.findElement(By.cssSelector("#searchArea > button:nth-child(5)")).click();driver.getTitle().equals("我的音乐收藏");}//测试搜索功能void love_search() throws IOException {driver.findElement(By.cssSelector("#musicSearch")).sendKeys("不");driver.findElement(By.cssSelector("#searchArea > button.btn.btn-primary")).click();getScreenShot("search");driver.findElement(By.cssSelector("#musicSearch")).clear();driver.findElement(By.cssSelector("#musicSearch")).sendKeys("唠赵头儿 - 不说");driver.findElement(By.cssSelector("#searchArea > button.btn.btn-primary")).click();getScreenShot("search");//重置driver.findElement(By.cssSelector("#searchArea > button.btn.btn-secondary")).click();}//返回主页功能void lovemusic_to_music(){driver.findElement(By.cssSelector("#searchArea > button:nth-child(5)")).click();driver.getTitle().equals("我的音乐收藏");}void delete() throws InterruptedException {String text=driver.findElement(By.cssSelector("#searchResults")).getText();Pattern pattern = Pattern.compile("\\d+");Matcher matcher = pattern.matcher(text);driver.findElement(By.cssSelector("#info > tr:nth-child(2) > td.operation-buttons > button:nth-child(1)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.accept();Thread.sleep(1000);Alert alert1=driver.switchTo().alert();alert1.accept();String text1=driver.findElement(By.cssSelector("#searchResults")).getText();Matcher matcher1 = pattern.matcher(text1);int i = 0,i1=0;if (matcher.find()) {i = Integer.parseInt(matcher.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i);}if (matcher1.find()) {i1 = Integer.parseInt(matcher1.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i1);}if(i==i1+1){System.out.println("删除成功");}}void delete_sel() throws InterruptedException {String text=driver.findElement(By.cssSelector("#searchResults")).getText();Pattern pattern = Pattern.compile("\\d+");Matcher matcher = pattern.matcher(text);driver.findElement(By.cssSelector("#\\37 7")).click();driver.findElement(By.cssSelector("#\\37 9")).click();driver.findElement(By.cssSelector("#searchArea > button:nth-child(4)")).click();Thread.sleep(1000);Alert alert=driver.switchTo().alert();alert.accept();Thread.sleep(1000);Alert alert1=driver.switchTo().alert();alert1.accept();String text1=driver.findElement(By.cssSelector("#searchResults")).getText();Matcher matcher1 = pattern.matcher(text1);int i = 0,i1=0;if (matcher.find()) {i = Integer.parseInt(matcher.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i);}if (matcher1.find()) {i1 = Integer.parseInt(matcher1.group()); // 获取匹配的字符串,并转换为整数System.out.println("找到的数字: " + i1);}if(i==i1+2){System.out.println("删除成功");}}
}
(6)创建未登录状态下测试用例类
创建 No_Login 类,在这里编写未登录状态下的所有测试用例,在这里我们要完成的事情如下:
- 未登录状态下访问Music_List界面
- 未登录状态下访问Music_Love界面
package 界面测试;
import common.Utils;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class No_Login extends Utils {public No_Login(String url) {super(url);}void music_list() throws InterruptedException {
// driver.get("http://127.1.0.0:8080/list.html");Thread.sleep(3000);Alert alert=driver.switchTo().alert();alert.getText().equals("没有登录!");alert.accept();}void music_love() throws InterruptedException {driver.findElement(By.cssSelector("#searchArea > button:nth-child(5)")).click();Thread.sleep(3000);Alert alert=driver.switchTo().alert();alert.getText().equals("没有登录!");alert.accept();}}
(7)创建运行测试用例类
创建 Test 类, 在这里进行所有测试代码的运行,我们要以合理的方式调用每一个页面的所有测试方法,来进行在线音乐播放器的 UI 自动化测试,关于 Test 的具体代码及详细介绍如下所示
package 界面测试;import java.io.IOException;public class Test {static String url = "http://127.1.0.0:8080/login.html";public static void main(String[] args) throws IOException, InterruptedException {Login login = new Login("http://127.1.0.0:8080/login.html");//首先错误登录login.false_login();//然后正确登录login.login();Music_List musicList=new Music_List("http://127.1.0.0:8080/list.html");//界面测试musicList.list();//搜索musicList.search();//收藏musicList.love();//删除musicList.delete();//上传musicList.upload();//批量删除音乐musicList.delete_sel();Music_Love musicLove=new Music_Love("http://127.1.0.0:8080/lovemusic.html");//搜索音乐musicLove.love_search();//删除音乐musicLove.delete();//批量删除音乐musicLove.delete_sel();//返回主页musicLove.lovemusic_to_music();//未登录状态下No_Login noLogin=new No_Login("http://127.1.0.0:8080/list.html");//访问主界面noLogin.music_list();//访问喜欢音乐界面noLogin.music_love();}
}
3.自动化测试执行结果
我们在 RunTest 类中进行运行,运行的过程及结果如下图所示:
主界面测试
收藏音乐界面测试
未登录状态下测试
如上图运行过程所示,我们的自动化测试用例全部通过,在执行自动化测试的时候,我们要注意多次执行的时候,在上传音乐的方法中要更改新的上传音乐,否则就会上传音乐失败,在执行失败的时候要多用屏幕截图来抓取当时出错的场景。
六.性能测试
下面我来使用 JMeter 对在线音乐播放器项目的登录接口和获取音乐列表接口进行简单的性能测试,下面就来介绍在线音乐播放器项目性能测试的一个测试流程。
1.创建梯度压测线程组
这里我们创建一个梯度压测线程组(Stepping Thread Group),来慢慢增大我们对这两个接口的并发请求的数量,创建的梯度压测线程组的具体配置如下图所示:
2.创建 HTTP 请求默认值
在在线音乐播放器项目中涉及到的接口协议、IP、端口号及内容编码都完全一样,所以我们就可以把这些单独抽取出来,存放在默认值中,这样其他接口就可以省略不写协议、IP、端口号及内容编码了,这里我们具体设置的默认值如下图所示:
3.创建 HTTP Cookie 管理器
如果我们在未登录状态进行获取音乐列表的操作,将会获取到一个空的音乐列表,这显然是不科学的,所以为了我们可以获取到登录请求中用户的用户信息就需要添加一个 HTTP Cookie 管理器,它会像浏览器一样存储和发送 Cookie ,如果我们 HTTP 请求返回的响应中包含 Cookie 那么 Cookie 管理器就会自动存储该 Cookie,并把这个 Cookie 用于后面特定的请求中,所以添加了 HTTP Cookie 管理器后,就会自动存储并发送 Cookie,添加的管理器如下图所示:
4.创建音乐播放器登录请求
根据在线音乐播放器项目中用户登录的接口来编写用户登录请求的内容,具体内容如下图所示
5.创建获取音乐列表页请求
根据在线音乐播放器项目中获取音乐列表请求接口来编写获取音乐列表的内容,具体内容如下图所示:
6.性能测试执行结果
执行性能测试之前,我们添加以下四个监听器,它们的用途如下所示
- Active Thread Over Time:这是用来记录每一时刻存活线程的数目,最后形成一个图表;
- Transactions per Second(TPS):这个监听器是用来分析系统吞吐量的重要工具。TPS 即每秒事务数,表示一个客户机向服务器发送请求后服务器做出反应的过程,这个指标反映了系统在同一时间内处理业务的最大能力,TPS 越高,说明系统的处理能力越强。
- Response Times Over Time:这个监听器是用来监听整个事务运行期间的响应时间,在测试过程中,它可以帮我们观察并分析响应时间的实时平均值以及整体响应时间的走向,通过这个监听器,我们可以更直观的了解系统中不同时间点的响应性能,从而发现可能存在的性能问题;
- 聚合报告:通过这个报告,可以看到性能测试过程中整体的数据变化。
下面我们开始执行性能测试,关于各监听器执行后的结果,如下图所示:
7.生成性能测试报告
执行完成性能测试之后,我们需要出具一份性能测试报告,这个报告不用我们手动进行编写,而是通过命令的方式使用 JMeter 来自动帮我们生成,具体操作如下图所示:
关于上图中命令所涉及参数的含义,具体介绍如下所示:
- -n:以无图形化运行;
- -t:被运行的脚本;
- -l:将运行信息写入日志文件,后缀为 jtl 的日志文件;
- -e:生成测试报告;
- -o:指定报告输出目录。
注意:日志文件和目录可以不存在,若已经存在,要保证内容为空,否则会出现错误。
那么测试报告生成之后,在 网页版音乐播放器性能测试报告 文件夹下将出现如下图所示的内容:
双击 index.html 文件,界面展示如下:
关于性能测试报告的具体内容我在这里就不进行过多展示了,感兴趣的小伙伴我会把这个报告附在本篇文章中,可以自行观察。