- 设计测试用例
- 实现博客系统自动化测试的登录、编辑、查看、删除以及注销等功能
- 完成对博客系统的性能测试
目录
前言
让我们用selenium自动化测试,看看这个web项目是否达到了预期,再用LoadRunner测试一下该系统的性能如何吧~
一、项目介绍
-
注册账号:输入用户名、密码,再次输入确定密码即可注册成功。
-
登录功能:输入正确的用户名和密码即可登录成功,然后跳转至博客列表页面。右上角有主页、写博客和注销三个按钮,在未登录情况下点击均跳至登录页面。
-
在登陆之后的任意界面点击“写博客”就会进入博客编辑页面,点击“发布文章”后跳转至列表页。
-
列表页面:可以在列表页查看有限数量的博客简介。其中包括博客标题、发布时间以及内容概要。页面左侧可以看到登录的用户以及文章数、github地址等模块。右上角有主页、写博客和注销三个按钮。
-
详情页面:在列表页面点击“查看原文”按钮就会跳转到详情页,此时就可以看到该篇博客的完整内容。
-
删除功能:点击“删除博客”按钮,页面跳转至博客列表页,不再有该条博客信息。
-
注销账号:点击“注销”按钮,页面跳转至登录页。
二、功能测试
(一)编写测试用例
1.通过正交表设计测试用例(举例登录情况)
2.测试用例如下:
(二)使用Selenium进行Web自动化测试
1. 添加相关依赖pom.xml
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.59</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.15.0</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.9.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.9.1</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite</artifactId>
<version>1.9.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>
</dependencies>
2.新建包并在包中建立测试类以及公共类
3.初始化:创建驱动、打开浏览器、关闭浏览器
4.博客登录页自动化测试
创建一个类(自定义名为BlogCases)继承InitAndEnd类,得到驱动,然后再这个类下分别对打开网页是否正常,并使用参数化注解对登录模块进行测试。
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.openqa.selenium.*;
import java.util.concurrent.TimeUnit;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{ //继承的好处:对应的每一个测试用例都有了一个浏览器驱动
@Order(1)
@ParameterizedTest
@CsvFileSource(resources = "/test01.csv")
void LoginSuccess(String username,String password,String blog_list_url) {
System.out.println(username + password + blog_list_url);
//打开博客登陆页面
webDriver.get("http://47.115.201.203:8080/login.html");
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//输入账号test123
webDriver.findElement(By.cssSelector("#username")).sendKeys(username);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//输入密码123456
webDriver.findElement(By.cssSelector("#password")).sendKeys(password);
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//点击提交按钮
webDriver.findElement(By.cssSelector("#submit")).click();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//跳转到列表页
//获取到当前页面的url
String cur_url = webDriver.getCurrentUrl();
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
//如果url=http://47.115.201.203:8080/blog_list.html,测试通过;否则测试不通过
Assertions.assertEquals(blog_list_url.contains("http://47.115.201.203:8080/blog_list.html"),cur_url.contains("http://47.115.201.203:8080/blog_list.html"));
//列表页展示用户信息是test123
//用户名是test123,测试通过;否则测试不通过
webDriver.manage().timeouts().implicitlyWait(3, TimeUnit.SECONDS);
String cur_admin = webDriver.findElement(By.cssSelector("body > div.container > div.container-left > div > h3")).getText();
Assertions.assertEquals(username,cur_admin);
}
}
测试结果如下:
5.博客列表页自动化测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.openqa.selenium.*;
import java.util.concurrent.TimeUnit;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{ //继承的好处:对应的每一个测试用例都有了一个浏览器驱动
/*
* 列表页博客数目不为0
* */
@Order(2)
@Test
void BlogList(){
//打开博客列表页
webDriver.get("http://47.115.201.203:8080/blog_list.html");
//获取页面上所有博客标题对应的元素
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
int title_num = webDriver.findElements(By.cssSelector(".title")).size();
//如果元素数量不为0,测试通过
Assertions.assertNotEquals(0,title_num);
}
}
测试结果如下:
6.博客编辑页自动化测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static java.lang.Thread.sleep;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{
/*
写博客
*/
@Order(3)
@Test
void EditBlog() throws InterruptedException {
//找到写博客按钮,点击
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(4)")).click();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
//通过JS脚本将标题进行输入
((JavascriptExecutor)webDriver).executeScript("document.getElementById(\"title\").value=\"出现一下\"\n");
sleep(3000);
WebDriver webDriver =new ChromeDriver();
Actions actions = new Actions(webDriver) ;
sleep(3000);
//点击发布
webDriver.findElement(By.cssSelector("#submit")).click();
sleep(3000);
//获取当前页面的url
String cur_url = webDriver.getCurrentUrl();
Assertions.assertEquals("http://47.115.201.203:8080/blog_list.html",cur_url);
}
}
测试结果如下:
7.博客详情页自动化测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static java.lang.Thread.sleep;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{
/*
* 博客详情页校验
* url
* 博客标题
* 页面title
* */
@Order(4)
@ParameterizedTest
@MethodSource("Generator")
void BlogDetail(String expected_url,String expected_title,String expected_blog_title){
//找到第一篇博客对应的查看全文按钮
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a:nth-child(4)")).click();
//获取当前页面的url
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
String cur_url = webDriver.getCurrentUrl();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
//获取当前页面title
String cur_title = webDriver.getTitle();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
//获取详情页标题
String cur_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > h3")).getText();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
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(cur_url);
System.out.println("测试失败");
}
}
}
测试结果如下:
8.博客发布时间、发布标题测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static java.lang.Thread.sleep;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{
/*校验已发布博客的标题
* 校验已发布博客的时间
*/
@Order(5)
@Test
void BlogInfoCheck(){
webDriver.get("http://47.115.201.203:8080/blog_list.html");
//获取第一篇博客的标题
String first_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
//获取第一篇博客的发布时间
String first_blog_time = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.date")).getText();
//校验博客标题
Assertions.assertEquals("出现一下",first_blog_title);
//如果时间是2023.11.30发布的,测试通过
if (first_blog_time.contains("2023-11-30")){
System.out.println("测试通过");
}else {
System.out.println("当前时间是 : " +first_blog_time);
System.out.println("测试不通过");
}
}
}
9.删除博客自动化测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static java.lang.Thread.sleep;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{
/*
* 删除刚才发布的博客
*/
@Order(6)
@Test
void DeleteBlog(){
//打开博客列表页面
webDriver.get("http://47.115.201.203:8080/blog_list.html");
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
//点击删除按钮
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > a:nth-child(6)")).click();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
//博客列表页第一篇博客标题不是"自动化测试"
String first_blog_title = webDriver.findElement(By.cssSelector("body > div.container > div.container-right > div:nth-child(1) > div.title")).getText();
//校验相不相等
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
Assertions.assertNotEquals("自动化测试",first_blog_title);
}
}
测试结果如下:
10.注销博客自动化测试
package Blog;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvFileSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.interactions.Actions;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import static java.lang.Thread.sleep;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BlogCases extends InitAndEnd{
/*
* 注销
* */
@Order(7)
@Test
void LogOut(){
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
webDriver.findElement(By.cssSelector("body > div.nav > a:nth-child(5)")).click();
webDriver.manage().timeouts().implicitlyWait(3,TimeUnit.SECONDS);
String cur_url = webDriver.getCurrentUrl();
Assertions.assertEquals("http://47.115.201.203:8080/login.html",cur_url);
//检验提交按钮(把登陆按钮检测到的放在变量里)
WebElement webElement = webDriver.findElement(By.cssSelector("#submit"));
Assertions.assertNotNull(webElement);
}
}
测试结果如下:
11.自动化测试总结
(三)功能测试总结
- 初始化进行一次驱动的创建,避免每个测试用例重复创建驱动造成时间和资源的浪费
- 在博客的登录和博客详情页的测试中用到了参数化,使编写的测试用例更加简洁,提高了代码的可读性
- 有时候代码没问题也会报错——找不到对应的元素,此时需要添加隐式等待,当页面元素加载完了,程序才会往下执行。使用隐式等待,提高了自动化运行的效率和稳定性
- 使用了Junit5中提供的注解,避免生成过多的对象,造成资源和时间的浪费,提高了自动化的执行效率
- 当发现多参数(多用户登录)时会出现高并发的服务器错误问题,该情况需交给开发人员处理
- 适当关注测试用例的执行时间,时间过长可能就需要考虑是写的测试用例的问题还是程序真的有性能问题
三、性能测试
使用loadrunner针对登录功能进行简单的性能测试,然后在实现的过程中,插入集合点以及事务等,并通过设置来实现用户的并发操作。
(一)Virtual User Generator
1.脚本加强
Action()
{
lr_rendezvous("rendezvous1"); //设置集合点
lr_start_transaction("login"); //设置开始事务
web_submit_data("login",
"Action=http://47.115.201.203:8080/user/login",
"Method=POST",
"RecContentType=text/html",
"Referer=http://47.115.201.203:8080/login.html",
"Snapshot=t6.inf",
"Mode=HTML",
ITEMDATA,
"Name=user"
"name", "Value=test123", ENDITEM,
"Name=password", "Value=123456", ENDITEM,
EXTRARES,
"Url=../blog/getAll", "Referer=http://47.115.201.203:8080/blog_list.html;jsessionid=5161E4D9AF3E0FF270B77D09F3D6A11F", ENDITEM,
"Url=loginer", "Referer=http://47.115.201.203:8080/blog_list.html;jsessionid=5161E4D9AF3E0FF270B77D09F3D6A11F", ENDITEM,
LAST);
lr_end_transaction("login", LR_AUTO); //设置结束事务
lr_log_message("登陆成功!");
return 0;
}
2.操作关键步骤
3.运行结果
(二)Controller
1.设置场景
2.运行结果
(三)Analysis
1.报告
2.并发用户数
作用:可以通过显示的虚拟用户数量判断出哪个时间段服务器负载最大(上图00:40 ~ 01:40负载最大)
3.每秒产生点击服务器的次数(点击率)
作用:通过点击率可以判断出某时间段内服务器的负载。
4.吞吐量
作用:通过吞吐量可以反映响应返回的资源数量,先有请求后有返,因此吞吐量图略微滞后点击数图且大致趋势相同。
5.事务综述图
6.平均事务响应时间
作用:虚拟用户在性能测试中,每秒在服务器上命中的次数,由此可以评估生成的负载量。