1.项目背景
论坛博客系统采用前后端分离的方法来实现,同时使用了数据库来存储相关的数据,同时将其部署到云服务器上。前端主要有四个页面构成:登录页、列表页、详情页以及编辑页,以上模拟实现了简单的论坛系统。其结合后端将支持用户注册、登录、发帖、回帖、点赞、私信等基本功能。系统将具备良好的安全性。系统将支持高并发处理,确保在用户量剧增时依然能够稳定运行。该论坛系统可以实现个人用户简单的文章记录,时间、标题、内容以及发布者等都可以进行详细地查看。
1.1测试目标
主页面测试覆盖达到90%
1.2被测系统
forum: 基于spring的论坛系统-前后端分离 (gitee.com)
1.3 测试接口
根据Swagger自动生成的Api说明文档,编写接口测试用例,利用Jmeter完成接口测试
http://127.0.0.1:58080/swagger-ui/index.html#
1.3测试计划
测试类别 | 测试工具 |
功能测试 | 手动 |
接口测试 | Swagger、postman |
自动化测试 | selenium |
性能测试 | jmeter |
2.测试分类
2.1功能测试
该个人博客系统主要实现了以下几个功能:登录、注销、写博客以及删除博客等功能。
- 注册功能:用户进入登录页后如果没有账号可以进行注册,点击注册按钮后进入用户注册页面,完善相关信息后点击注册即可注册账号。
- 登录功能:用户在注册完成之后进行账号登录,登录成功后就会跳转到列表页面。在右上角存在发布帖子按钮,但是在未登录情况下按下均只会跳转到登录页面。
- 编辑个人信息功能:右上角点击个人头像会弹出个人中心以及退出按钮,点击个人中心即可跳转到个人信息编辑页面。
- 列表页面:可以在列表页查看有限数量的帖子简介,其包括作者、标题、发布时间以及内容概要。在上侧可以看到分类的模块。在右上角有主页、写博客和退出三个功能:主页即列表页,写文章即帖子编辑页,退出即退出账号,回到登录页面。
- 发布帖子功能:在登录之后的界面点击“发布帖子”之后就会进入编辑页面,此时就可以进行帖子的编写,点击“发布”后就可以成功发布文章,此时就会跳转到列表页。
- 删除帖子功能:用户在点击自己的帖子之后会跳转到帖子详情页,右下角有点赞、删除和编辑帖子的按钮,点击之后即可操作。
- 修改帖子功能:用户在点击自己的帖子之后会跳转到帖子详情页,右下角有点赞、删除和编辑帖子的按钮,点击之后即可操作。
- 发送/读取站内信功能:用户登录后右上角有站内信提示按钮,点击后即可发送和读取站内信。
2.1.1测试用例
2.1.2执行操作步骤/截图
1)正常登录
2)编辑帖子测试
3)发布成功并查看详情页
4)删除帖子
进入详情页并点击“删除”后再次点击“删除”之后成功删除,刚才做发布的“游啊游”已经被成功删除。
5)点赞功能:点击进入帖子详情页后点击“点赞”按钮,点赞数显示加一。
6)发送站内信:点击进入帖子详情页后点击“发私信”按钮即可编辑站内信,点击发送即可成功发出。
-
- 退出:用户登录后右上角有站内信提示按钮,点击后即可发送和读取站内信。
3.测试结果
测试用例100%通过
2.2界面测试
2.2.1测试用例
2.2.2测试结果
符合预期。
2.3兼容性测试
2.3.1测试用例
2.3.2测试执行
不同浏览器:Microsoft Edge与Google Chrome
不同设备:移动端
2.3.3测试结果
符合预期。
2.4易用性测试
2.4.1测试用例
2.4.1测试结果
符合预期。
2.5自动化测试
针对论坛系统项目进行测试,主要负责四个模块:登录页、列表页、详情页和编辑页,主要功能包括:登录、编辑并发布帖子、查看详情、删除博客以及退出等功能。对于论坛系统的测试主要就是针对主要功能进行测试,然后按照页面书写测试类。
2.5.1测试用例
以页面书写测试类,然后对主要功能进行测试。
2.5.2 脚本编写
a.根据脑图进行测试用例的编写:每个页面一个测试类,然后再各个测试类中进行测试用例的编写。
b.注意公共属性需要单独放一个类,方便进行代码复用。
c.使用测试套件便于运行以及修改。
d.创建启动以及现场截图就是会频繁进行复用,所以单独创建一个类进行存储。
e.注意添加隐式等待,为了确保页面正确加载显示。
i 添加相关依赖pom.xml
ii 新建包并在包下创建测试类以及公共类
<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>
按照页面分类,每个页面是一个Java文件,页面下所有的用例统一管理。
- 公共类Utils
创建驱动对象、等待、保存现场截图
ps:在保存现场截图的时候命名是按时间来进行文件夹的划分,然后图片的名称要体现出测试类的类名,方便进行问题的追溯。
注意文件名的动态获取,注意时间格式的设置。
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(2));
}
return driver;
}
public Utils(String url){
//调用driver对象
driver = createDriver();
//访问url
driver.get(url);
}
//截图
public void getScreenShot(String str) throws IOException {
//文件夹格式
SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd");
//图片格式
SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS"); //SS:毫秒级别
String dirTime = sim1.format(System.currentTimeMillis()); //获取当时时间戳
String fileTime = sim2.format(System.currentTimeMillis()); //文件名为当天日期
//./src/test/image/2024-07-17/test01-184033.png 预期截图保存路径
String filename = "./src/test/image/"+dirTime+"/"+ str +"-" + fileTime +".png";
File srcfile = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); //输出为文件形式
FileUtils.copyFile(srcfile,new File(filename));
}
}
- 登录页面测试LoginPage.java
① 创建驱动,并打开页面
② 测试页面是否正常打开
③ 测试正常登录:多参数测试
④ 测试异常登录:用户名/密码错误的情况
⑤ 注意测试的顺序,可能会因为执行顺序不对导致测试失败
⑥ 注意清空内容后才能再次输入用户名以及密码
public class LoginPage extends Utils {
public static String url = "http://121.40.27.219:58080/sign-in.html";
public LoginPage(){
super(url);
}
/*检查页面是否加载成功*/
public void LoginPageRight() throws IOException, InterruptedException {
//通过查看页面元素是否存在来检查页面是否加载成功
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.text-center.mb-4 > img"));
//登录输入框
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div"));
getScreenShot(getClass().getName());
}
/*检查能否正常登录*/
//检查登录功能----成功登录
public void LoginSuc() throws IOException, InterruptedException {
driver.findElement(By.cssSelector("#username")).sendKeys("duan");
driver.findElement(By.cssSelector("#password")).sendKeys("123456");
driver.findElement(By.cssSelector("#submit")).click();
//检查点击后是否加载成功
driver.findElement(By.cssSelector("#article_list_board_title"));
//通过页面标题检查是否登录成功
String expect = driver.getTitle();
assert expect.equals("小小论坛");
// getScreenShot(getClass().getName());
// driver.navigate().back();
// driver.findElement(By.cssSelector("#topBannerBox > div > div.right-menu > div > div > i")).click();
// Alert alert = driver.switchTo().alert();
// alert.accept();
// System.out.println("111");
// driver.findElement(By.xpath("/html/body/ul/li[2]")).click();
// driver.get(url);
}
//检查登录功能----登录失败
public void LoginFail() throws IOException {
/*输入错误信息*/
//返回登录页
driver.navigate().back();
//法一:通过clear清空输入框
driver.findElement(By.cssSelector("#username")).clear();
driver.findElement(By.cssSelector("#password")).clear();
//法二:刷新清空输入框
driver.navigate().refresh();
driver.findElement(By.cssSelector("#username")).sendKeys("zhangsan");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#submit")).click();
//通过查找警告框是否存在来检查登录是否失败
driver.findElement(By.cssSelector("body > div.jq-toast-wrap.bottom-right > div"));
getScreenShot(getClass().getName());
}
}
列表页测试ListPage.java
① 测试帖子列表页是否可以正常打开
② 测试列表页是否可以正常跳转至详情页
③ 测试未登录的直接链接是否会跳转到登录页面,顺便测试了“退出”按钮
public class ListPage extends Utils {
public static String url = "http://121.40.27.219:58080/index.html";
public ListPage() {
super(url);
}
/* 未登录状态下---访问列表页*/
public void ListNoLogin() throws IOException {
getScreenShot(getClass().getName());
//1.保证未登录状态
// driver.navigate().back();
driver.navigate().refresh();
driver.findElement(By.cssSelector("body > div > div > div > div:nth-child(1) > div > div.card.card-md > div"));
//driver.get(url);
//通过查询列表页的元素来判断是否进入列表页
driver.findElement(By.cssSelector("#bit-forum-content > div.page-body > div > div > div > div > div"));
}
}
- 编辑页测试EditPage.java
① 测试编辑页是否可以正确打开
② 测试帖子是否可以正常发布:元素齐全 or 部分元素
③ 测试“发布帖子”按钮是否可以正常使用
④ 由于编辑列表是第三方插件可能出现无法交互异常报错
Solution:本身存在内容/使用键盘操作
public class EditPage extends Utils {
public static String url = "http://121.40.27.219:58080/article.html";
public EditPage() {
super(url);
}
public void EditSuc() throws InterruptedException {
driver.findElement(By.cssSelector("#article_post_title")).sendKeys("测试01");
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(2));
// wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("#edit_article_content_area > div.CodeMirror.cm-s-default.CodeMirror-wrap > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre")));
WebElement ele = driver.findElement(By.cssSelector("#edit-article > div.CodeMirror.cm-s-default.CodeMirror-wrap.CodeMirror-empty > div.CodeMirror-scroll > div.CodeMirror-sizer > div > div > div > div.CodeMirror-code > div > pre"));
Actions actions = new Actions(driver);
//perform() 为了在页面看到效果
actions.doubleClick(ele).perform();
actions.keyDown(Keys.DELETE).perform();
actions.moveToElement(ele).sendKeys("测试01").perform();
Thread.sleep(3000);
driver.quit();
}
}
- 详情页测试DetailPage.java
① 测试详情页的正确打开:有Id和没有Id两种情况
② 测试“删除”按钮是否可用,注意比较的是时间,因为标题可能会存在为空的情况
③ 执行顺序
④ 一定要注意导航回到列表页的操作
public class DetailPage extends Utils {
public static String url = "http://121.40.27.219:58080/index.html";
public DetailPage() {
super(url);
}
public void DetailSuc() throws InterruptedException {
//点击帖子进入详情页
driver.findElement(By.cssSelector("#artical-items-body > div:nth-child(1) > div > div.col > div.text-truncate > a > strong")
).click();
//通过查找详情页的元素来判断是否进入详情页
driver.findElement(By.cssSelector("#bit-forum-content > div.page-body > div > div > div:nth-child(1) > div.col-9.card.card-lg"));
}
}
2.5.3测试结果
自动化测试用例数量 | 2 |
自动化测试结果 | pass:2/2 |
问题是否修复 | 是 |
2.6 性能测试
使用jmeter进行简单性能测试:针对登录、编写并发布帖子以及删除帖子、退出等功能进行简单的性能测试。
然后在实现的过程中,插入集合点以及事务等,并通过设置来实现用户的并发操作。
2.6.1 弱压力场景
模拟5分钟之内 1000 个用户访问服务器资源,这里访问博客列表,要求平均响应时间在300ms内,且错误率为0。
符合要求。
2.6.2高并发场景
模拟 100 个用户同时访问服务器资源,要求平均响应时间在300ms内,且错误率为0。
符合预期。
2.6.3高频率场景
模拟2个用户以20QPS的频率访问服务器资源持续10秒,要求平均响应时间在300ms内,错误率为0。
符合预期。
3.测试总结
3.1 功能测试:验证了用户注册、登录、发帖、回帖、编辑和删除帖子等核心功能的正确性和完整性。测试结果显示,所有功能均按预期工作,无重大缺陷。
3.2 接口测试:通过自动化测试脚本对API进行了测试,确保了数据传输的准确性和安全性。测试覆盖了所有端点,包括用户认证、帖子管理和评论功能。
3.3 界面测试:对前端界面进行了视觉和布局测试,确保在不同设备和分辨率上均能提供一致的用户体验。界面响应式设计在多种屏幕尺寸下表现良好。
3.4 兼容性测试:系统在主流浏览器和操作系统上进行了测试,包括Chrome和Edge,确保了跨平台的兼容性。
3.5 易用性测试:通过用户测试收集了反馈,优化了用户界面和交互流程,提高了系统的用户友好度。测试结果表明,用户能够轻松地导航和使用系统。
3.6 性能测试:模拟了高并发用户访问场景。系统在测试中表现出良好的稳定性和响应速度,满足了性能要求。
综上所述,论坛系统在各项测试中表现稳定,满足了项目的质量标准,为上线做好了准备。