博客系统测试报告
一.博客系统功能测试报告
本博文主要针对个人实现的项目《博客系统》去进行功能测试、自动化测试、性能测试,并记录总结
1.功能测试
测试环境: win11 Chrome浏览器
①.注册功能测试
执行步骤: 访问网站-> 跳转到注册页面-> 输入测试数据 ->单击注册
针对注册功能的用户名输入 设计测试用例进行测试
根据用户名要求去划分有效等价类和无效等价类
以及根据长度要求划分出边界值:上点、内点、离点
最后组合有效等价类和无效等价类、边界值 数据 构造出测试点进行测试。
针对注册功能的密码输入 设计测试用例进行测试
根划分有效等价类和无效等价类 , 以及根据长度要求划分出边界值:上点、内点、离点
最后组合有效等价类和无效等价类、边界值 数据 构造出测试点进行测试。
综合上述的测试点对博客系统注册功能进行测试结果:
②.发布博文功能测试
访问网站->登录用户->单击个人主页->单击写博客->编辑博文->单击发布
针对发布博文要求: 文章标题 长度要在1~25 文章描述 长度 要在 5~100 文章正文长度 非空 进行测试
经过测试后验证发布博文功能符合预期:只有在标题长度在1~15 文章正文有内容 文章描述 在5~100 条件下 能成功发布博文
测试过程部分截图
文章描述低于五个字时
发布成功时:
③.删除博文功能测试
访问网站->登录用户->单击个人主页->选择某篇博文单击查看博文->单击删除博文
打开postman->构造cookie用户登录id->构造测试数据->单击发送删除博文请求
针对删除博文要求: 用户只能删除自己已发布的博文
扩展思维:用户不单单只能通过提供的删除博文进行博文删除操作,还可以通过其他工具去向后端发送请求执行删除博文操作
经过测试后 验证删除博文功能符合预期 : 用户能正常删除自己已发布的博文,尽管用户不通过删除博文按钮去执行删除功能也无法删除其他用户的博文
测试过程部分截图:
通过sql语句 查询到 所有用户发布的博文 , 测试通过postman去删除 用户1 的博文id为14的文章 , 而此时用户状态为牛牛用户
事先在Cookie 里填入获取牛牛用户的 JSESSIONID 会话值 (后续发送的请求就会被当做牛牛用户发送的请求)
构造post请求 填入对应的参数 , 表示去删除id为14的博文
预期结果:肯定是删除失败, 不能删除其他用户的文章
实际结果 删除博文失败
再测试删除 自己写的博文, 预期结果删除成功 返回状态码200 执行结果 删除成功返回状态码200
状态码为200 ,通过postman发送删除博文请求 处理成功
④.功能测试总结
以上三个功能皆设计了测试用例进行了测试,并且执行结果和预期结果一致,且均生成了对应的测试用例表
注册功能测试用例表
用例名称 | 用户注册系统 |
---|---|
测试目的 | 测试用户能通过正常的用户名和密码注册为新用户 |
测试前提 | 未注册新用户 |
测试流程 | 1)进入注册页面 2)输入事先准备的测试数据 (用户名和密码) |
预期结果 | 输入正确的用户名和密码时,注册成功跳转到登录页面, 反之则显示注册失败,提示重新输入 |
实际结果 | 实际结果和预期结果基本一致 |
发布博文测试用例表
用例名称 | 发布博文测试 |
---|---|
测试目的 | 测试用户发布博文功能 |
测试前提 | 已注册博客系统 |
测试流程 | 1)登录博客系统 2)进入博文编辑页 3)输入事先准备的测试数据 (博文内容) 4)单击发布博文 |
预期结果 | 输入合法的博文内容,显示发布成功跳转到博文列表页, 反之则显示发布博文失败 |
实际结果 | 实际结果和预期结果基本一致 |
删除博文测试用例表
用例名称 | 删除博文测试 |
---|---|
测试目的 | 测试用户删除博文功能 |
测试前提 | 已注册博客系统,已发布博文 |
测试流程 | 1. 1)登录博客系统 2)进入个人主页 3)单击查看全文4)单击删除博文 2. 使用postman工具调用删除博文接口 |
预期结果 | 删除自己已发布的博文,删除成功,返回博文列表页. 反之 提示删除失败,非法操作 |
实际结果 | 实际结果和预期结果基本一致 |
2.自动化测试
现采用Selenium搭配Junit一些Api对博客系统设计UI自动化测试用例,
主要针对核心功能: 用户登录、博文的增删查改、用户注销登录 功能进行测试。
①.测试初始化操作
进行测试前做一些准备工作:前置操作、后置操作 确认执行顺序,
确定测试方法执行顺序
1.登录失败测试,2.登录成功测试,3.写博文并查看测试,4.修改博文测试,5.删除博文测试,6.注销登录测试
针对这些测试功能编排测试顺序 利用前面测试产生的数据进行后续功能测试, 通过Junit 的 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)和@Order 注解实现
测试前置操作
创建浏览器驱动,设置智能等待、打开博文登录页,最大化页面
/**
* 前置操作 创建驱动 打开浏览器 最大化
*/
@BeforeAll
public static void setUp(){
webDriver=new ChromeDriver();
webDriver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS ); // 智能等待
webDriver.get("http://localhost:8080/blog_login.html"); // 打开博客系统网页
webDriver.manage().window().maximize(); // 最大化
}
测试后置操作
关闭浏览器 ,清除访问痕迹
/**
* 后置操作 关闭浏览器 清除痕迹
*/
@AfterAll
public static void tearDown(){
webDriver.quit(); // 彻底关闭博客系统网页
}
②.用户登录
用户登录测试 主要测试登录成功情况和登录失败情况 , 当前博客系统提供了图形验证码功能, 为了避免影响到登录测试,内置了万能验证码 **** 方便其一键跳过验证码检验。
登录失败测试
执行顺序:访问博客登录页, 输入预先准备的一些测试用例(正确用户名,错误密码)单击登录,
预期结果:页面不跳转,显示用户名或密码错误,登录失败
/**
* 博客系统登录失败测试方法
* @param username
* @param password
* @throws InterruptedException
*/
@ParameterizedTest
@Order(0)
@CsvFileSource(resources = "blog_login_error.txt")
public void loginError(String username,String password) throws InterruptedException {
String url = webDriver.getCurrentUrl();
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#judgetext")).sendKeys("****");
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(3000);
String actualUrl = webDriver.getCurrentUrl();
String message=webDriver.findElement(By.cssSelector("body > div.login-container > div > div.error")).getText();
Assertions.assertEquals("用户名或密码错误!", message);
Assertions.assertEquals(url,actualUrl); // 验证是否页面还是当前登录页面
webDriver.findElement(By.cssSelector("#username")).clear();
webDriver.findElement(By.cssSelector("#password")).clear();
webDriver.findElement(By.cssSelector("#judgetext")).clear();
}
采用多参数测试方法, 从文件中读取预先准备的登录失败测试数据
登录成功测试
执行顺序:访问博客登录页, 输入预先准备的正确用户名和密码,单击登录,
预期结果:跳转到博客列表页,登录成功
/**
* 博客登录成功测试方法
* @param username
* @param password
*/
@Order(1)
@ParameterizedTest
@CsvSource({"test,test123"})
public void loginSuccess(String username,String password) throws InterruptedException {
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.findElement(By.cssSelector("#judgetext")).sendKeys("****");
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
String name=webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3")).getText();
Assertions.assertEquals(username, name); // 验证登录后的对应框内是否是指定用户名
}
③.发布博文测试
执行顺序:在登录成功状态下, 单击个人主页 进入到个人主页->单击写博文 进入到博文编辑页 ->
输入符合要求的博文内容->单击发布,输入相应的文章描述信息->单击确认->跳转到个人主页->查看新发布的博文->博文发布成功
/**
* 添加\查看博文测试用例
* @param title
* @param content
* @param description
* @throws InterruptedException
*/
@Order(2)
@ParameterizedTest
//@CsvSource({"这是一篇测试博文,测试是否能正常发布博文,测试博文发布功能"})
@CsvFileSource(resources = "blog_add.txt")
public void addArticle(String title,String content,String description) throws InterruptedException {
sleep(2000);
//记录文章数
int count1 = Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > div:nth-child(6) > span.count")).getText());
// 进入个人主页
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(3)")).click();
// 写博文
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(7)")).click();
// 填写标题
webDriver.findElement(By.cssSelector("#title")).sendKeys(title);
// 通过js脚本代码 去往文章正文填写内容 要在textarea的value里输入内容 (内容要拼接‘’作为字符串执行)
((JavascriptExecutor)webDriver).executeScript("document.querySelector('textarea').value = "+"'"+content+"'");
//webDriver.findElement(By.cssSelector("#editor > textarea.editormd-html-textarea")).("测试是否能正常发布博文");
webDriver.findElement(By.cssSelector("#submit")).click();
// 填写描述信息
webDriver.switchTo().alert().sendKeys(description);
sleep(1000);
webDriver.switchTo().alert().accept(); // 单击确认
sleep(1000);
webDriver.switchTo().alert().accept(); // 单击确认
sleep(1000);
webDriver.switchTo().alert().accept(); //单击确认
sleep(1000);
// 获取更新后的文章数
Integer count2 = Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.card > div:nth-child(5) > span.count")).getText());
String actualTitle = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div > div.title")).getText();
// 判断文章数是否更新
Assertions.assertEquals(count1+1, count2);
// 判断标题是否一致
Assertions.assertEquals(title, actualTitle);
// 进入文章详情页
webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();
sleep(1000);
// 判断文章内容是否一致
String actualContent = webDriver.findElement(By.cssSelector("#content > p")).getText();
Assertions.assertEquals(content, actualContent);
}
④.修改博文测试
执行顺序: 在新增博文并查看博文后处于博文详情页, 单击修改博客按钮,进入博文编辑页->输入符合博文要求的内容对博文进行修改,单击发布博文->输入描述信息->单击确认,跳转到个人主页->修改成功
/**
* 博文修改测试方法
*
* @param title 修改的标题
* @param content 修改的正文
* @param description 修改的描述
* @throws InterruptedException
*/
@ParameterizedTest
@Order(3)
@CsvSource({"修改的标题,修改的测试正文,这是一篇测试博文"})
public void modifyArticle(String title,String content,String description) throws InterruptedException {
// 获取修改前的文章数
int count1 = Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.card > div:nth-child(5) > span.count")).getText());
// 修改文章内容
webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.option > button.mod")).click();
webDriver.findElement(By.cssSelector("#title")).clear();
webDriver.findElement(By.cssSelector("#title")).sendKeys(title);
// 通过js脚本去往textarea编辑框里输入内容
((JavascriptExecutor)webDriver).executeScript("document.querySelector('textarea').value = "+"'"+content+"'");
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(1000);
webDriver.switchTo().alert().sendKeys(description);
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
webDriver.switchTo().alert().accept();
// 修改后的文章总数
int count2= Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.card > div:nth-child(5) > span.count")).getText());
//总数应该不变
Assertions.assertEquals(count1, count2);
// 判断改后的标题
String actualTitle = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
Assertions.assertEquals(title, actualTitle);
}
⑤.删除博文测试
执行顺序:在已进入到个人主页,单击查看全文 进入博文详情页-> 单击删除博客按钮->单击确认,跳转到个人主页->博文删除成功
/**
* 测试删除 博文功能 文章数是否变化
* @throws InterruptedException
*/
@Test
@Order(4)
public void delArticle() throws InterruptedException {
int count1 = Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.card > div:nth-child(5) > span.count")).getText());
//单击查看全文
webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a")).click();
//单击删除
webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.option > button.del")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
int count2 = Integer.parseInt(webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div.card > div:nth-child(5) > span.count")).getText());
Assertions.assertEquals(count1-1, count2);
}
⑥.注销登录测试
已登录状态下,单击注销登录->单击确定 , 跳转到博客登录页-> 注销登录成功
/**
* 注销登录测试
* @throws InterruptedException
*/
@Test
@Order(5)
public void logout() throws InterruptedException {
//单击注销登录
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(8)")).click();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
webDriver.switchTo().alert().accept();
sleep(1000);
String mes = webDriver.findElement(By.cssSelector("body > div.login-container > div > h2")).getText();
//验证是否已经跳转到登录页面
Assertions.assertEquals("账号登录",mes);
}
自动化测试总结和展示
编写自动化测试脚本代码时,出现了一些异常情况:
1.未获取到某个元素 。
排查原因: 脚本执行速度快,此时页面还未渲染完
解决方法: 引入智能等待且,给相应代码前加入线程休眠。
2.参数化方法显示未获取到参数
排查原因: 使用了中文逗号
解决方法:将中文逗号换成英文逗号
3.通过选择元素输入文本,实际却文本却未被成功输入
排查原因: 其元素的文本值不应该在innerhtml中,而要输入在value属性中
解决方法: 将其转换为js脚本代码执行,将文本写入对应的元素的value属性中
最后展示自动化脚本代码的测试执行录制界面:
博客系统自动化测试