通过一系列的测试发现项目的以下bug:
使用Junit5+selenium对项目进行简单的自动化测试。
引入Junit5和selenium依赖
<dependency>
<groupId>org.junit.jupitergroupId>
<artifactId>junit-jupiterartifactId>
<version>5.8.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.junit.platformgroupId>
<artifactId>junit-platform-suiteartifactId>
<version>1.8.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.seleniumhq.seleniumgroupId>
<artifactId>selenium-javaartifactId>
<version>4.0.0version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.6version>
dependency>
为了方便自动化测试,这里关闭了项目的验证码功能。
为了避免在使用时频繁创建Chrome驱动类,我们可以定义一个功能类使用单例创建驱动对象。公共类里包含了保存截图的方法,方便测试截图观察。
public class AutoTestUtil {
private static volatile ChromeDriver driver;
private static final String IMG_SAVE_DIR = "./src/img/";
private AutoTestUtil(){}
public static ChromeDriver getDriver() {
if (driver == null) {
synchronized (AutoTestUtil.class) {
if (driver == null) {
ChromeOptions options = new ChromeOptions();
options.addArguments("--remote-allow-origins=*");
driver = new ChromeDriver(options);
// 设置隐式等待
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
}
}
}
return driver;
}
/**
* 获取格式化时间
* @return
*/
private static List<String> getTime() {
// 图片文件按照 包名.类名.方法名_时间搓区分
SimpleDateFormat fileFormat = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
// 图片目录按照天区分格式20230812
SimpleDateFormat dirFormat = new SimpleDateFormat("yyyyMMdd");
String fileName = fileFormat.format(System.currentTimeMillis());
String dirName = dirFormat.format(System.currentTimeMillis());
List<String> result = new ArrayList<>();
result.add(dirName);
result.add(fileName);
return result;
}
/**
* 截图
* @param testFuncName 对应函数名
* @throws IOException
*/
public static void saveFileImg(String testFuncName) throws IOException {
List<String> times = getTime();
String fileName = IMG_SAVE_DIR+times.get(0)+"/"+ testFuncName+"_"+times.get(1)+".png";
File file = driver.getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file,new File(fileName));
}
}
因为我这里是采用的隐式等待,隐式等待是对弹窗不起作用的,代码执行过快就会出现代码执行到点击弹窗确定按钮,而弹窗还没有出现。所以在点击之前将一个1秒的强制等待即可解决问题。
编写测试代码:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
保证测试用例的执行顺序// 使用方法排序
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
driver.get("http://120.25.124.200:7070/register.html");
driver.manage().window().maximize();
}
/**
* 检查注册页面是否正确打开
* 检测点:注册账号按钮是否显示
*/
@Test
@Order(1)
void regCheckLoad() {
driver.findElement(By.xpath("//*[@id=\"reg_submit\"]"));
}
/**
* 异常注册
* @param username
* @param password
* @param confirmPass
*/
@ParameterizedTest
@Order(2)
@CsvSource({"null,admin,admin","admin,null,admin","admin,admin,null","admin,admin,add","hhy,hhy,hhy"})
void regFail(String username,String password,String confirmPass) throws InterruptedException {
WebElement usernameElement = driver.findElement(By.cssSelector("#reg_username"));
WebElement passwordElement = driver.findElement(By.xpath("//*[@id=\"reg_password\"]"));
WebElement confirmPassElement = driver.findElement(By.cssSelector("#confirm_pass"));
if (!username.equals("null")) {
usernameElement.sendKeys(username);
}
if (!password.equals("null")) {
passwordElement.sendKeys(password);
}
if (!confirmPass.equals("null")) {
confirmPassElement.sendKeys(confirmPass);
}
driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();
Thread.sleep(2000);
// 点击警告弹窗的确认按钮
Alert alert = driver.switchTo().alert();
alert.accept();
usernameElement.clear();
passwordElement.clear();
confirmPassElement.clear();
}
/**
* 正常注册
* @param username
* @param password
* @param confirmPass
*/
@Order(3)
@ParameterizedTest
@CsvSource({"admin,admin,admin"})
void regSuccess(String username,String password,String confirmPass) throws InterruptedException {
driver.findElement(By.cssSelector("#reg_username")).sendKeys(username);
driver.findElement(By.cssSelector("#reg_password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"confirm_pass\"]")).sendKeys(confirmPass);
driver.findElement(By.cssSelector("#reg_submit")).click();
// 检测登录页面的元素来判断是否注册成功跳转
// 检测登录按钮+注册连接
driver.findElement(By.xpath("//*[@id=\"submit\"]"));
driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));
Thread.sleep(1500);
}
@AfterAll
static void quit() {
driver.quit();
}
}
自动化测试演示
根据测试用例编写对应代码:
@Suite
@SelectClasses(LogInAutoTest.class)
public class RunSuite {
}
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class LogInAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
driver.get("http://120.25.124.200:7070/login.html");
driver.manage().window().maximize();
}
/**
* 检测登录页面是否正确打开
* 检测点:注册链接、登录按钮
*/
@Test
@Order(1)
void loginCheckLoad() {
driver.findElement(By.xpath("/html/body/div[2]/div[5]/a[1]"));
driver.findElement(By.xpath("//*[@id=\"submit\"]"));
}
/**
* 正常登录
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"admin,admin","hhy,hhy"})
@Order(3)
void loginSuccess(String username,String password) throws IOException, InterruptedException {
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
// 强制等待避免误截图
Thread.sleep(1000);
//将登录成功后的用户博客列表页面进行截图
AutoTestUtil.saveFileImg(getClass().getName());
driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
Thread.sleep(1000);
alert.accept();
}
/**
* 异常登录
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"null,null","null,admin","admin,null","admin,123","hello,000"})
@Order(2)
void loginFail(String username,String password) throws InterruptedException {
WebElement usernameElement = driver.findElement(By.xpath("//*[@id=\"username\"]"));
WebElement passwordElement = driver.findElement(By.cssSelector("#password"));
if (!"null".equals(username)) {
usernameElement.sendKeys(username);
}
if (!"null".equals(password)) {
passwordElement.sendKeys(password);
}
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
// 强制等待防止弹窗未出现
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
usernameElement.clear();
passwordElement.clear();
}
@AfterAll
static void quit() {
driver.quit();
}
}
自动化执行演示:
登录自动化执行完毕后,8个用例全部执行成功,保存了用户博客列表页面的截图。
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UserBlogListAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
driver.manage().window().maximize();
}
/**
* 未登录访问
*/
@Test
@Order(1)
void userBlogListFail() {
driver.get("http://120.25.124.200:7070/user_blog_list.html");
// 获取当前页面url,判断未登录情况下是否跳转
String url = driver.getCurrentUrl();
Assertions.assertEquals("http://120.25.124.200:7070/login.html",url);
}
/**
* 进行正确登录
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"admin,admin"})
@Order(2)
void loginSuccess(String username,String password) {
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
}
/**
* 登录后访问
* 检测点:写博客链接,用户文章标题
*/
@Test
@Order(3)
void userBlogListSuccess() {
driver.get("http://120.25.124.200:7070/user_blog_list.html");
driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[2]"));
driver.findElement(By.cssSelector("body > div.content > div.mid > div.show > div > h4"));
}
@AfterAll
static void quit() throws InterruptedException {
// 注销
driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
Thread.sleep(1000);
alert.accept();
driver.quit();
}
}
自动化演示:
在进行修改信息页面测试时,发现无法找到昵称输入框,已经做了隐式等待。排查发现修改信息是在新窗口打开的,所以要通过代码切换窗口来处理。
通过句柄跳转到用户个人信息页面
// 获取博客列表页面句柄
String windows = driver.getWindowHandle();
// 点击修改资料链接
driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();
// 获取所有页面句柄
Set<String> windowHandles = driver.getWindowHandles();
for (String s : windowHandles) {
if (!s.equals(windows)) {
// 切换到用户信息页面
driver.switchTo().window(s);
}
}
自动化测试代码:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class UpdateUserInfoAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
}
/**
* 未登录状态下访问用户信息修改页面
*/
@Test
@Order(1)
void updateUserInfoFail() {
driver.get("http://120.25.124.200:7070/updateInfo.html");
driver.manage().window().maximize();
}
/**
* 进行正确登录
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"admin,admin"})
@Order(2)
void loginSuccess(String username,String password) {
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
}
/**
* 登录成功场景,修改个人昵称
*/
@Order(3)
@Test
void updateUserInfoSuccess() throws InterruptedException {
// 获取博客列表页面句柄
String windows = driver.getWindowHandle();
// 点击修改资料链接
driver.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[3]/a")).click();
// 获取所有页面句柄
Set<String> windowHandles = driver.getWindowHandles();
for (String s : windowHandles) {
if (!s.equals(windows)) {
// 切换到用户信息页面
driver.switchTo().window(s);
}
}
Thread.sleep(1000);
// 修改基本信息
driver.findElement(By.cssSelector("#netName")).clear();
driver.findElement(By.cssSelector("#netName")).sendKeys("网友");
// 提交修改
driver.findElement(By.xpath("//*[@id=\"submitInfo\"]")).click();
// 点击弹窗确认按钮
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
}
/**
* 登录状态上传头像错误格式,大小错误
*/
@Order(4)
@ParameterizedTest
@CsvSource({"C:\\Users\\HeHanYu\\Desktop\\code\\test.txt","C:\\Users\\HeHanYu\\Desktop\\壁纸\\wallhaven-d6eylg.jpg"})
void updateUserPhotoFail(String filePath) throws InterruptedException {
// 获取文件上传按钮
WebElement element = driver.findElement(By.cssSelector("#uploadImg"));
// 指定路径选择文件
element.sendKeys(filePath);
// 点击上传头像
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
Thread.sleep(800);
// 回退
driver.navigate().back();
}
/**
* 头像上传成功
* @throws InterruptedException
*/
@Order(5)
@Test
void updateUserPhotoSuccess() throws InterruptedException {
// 获取文件上传按钮
WebElement element = driver.findElement(By.xpath("//*[@id=\"uploadImg\"]"));
// 指定路径选择文件
element.sendKeys("C:\\Users\\HeHanYu\\Desktop\\code\\Python.jpg");
Thread.sleep(1500);
// 点击上传头像
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
// 回退
driver.navigate().back();
}
@AfterAll
static void quit() throws InterruptedException {
// 注销
driver.findElement(By.xpath("/html/body/div[1]/span[4]/a[3]")).click();
Thread.sleep(1000);
Alert alert = driver.switchTo().alert();
alert.accept();
Thread.sleep(1000);
alert.accept();
driver.quit();
}
}
自动测试执行完成后,测试用例全部通过
自动化测试演示:
根据用例编写代码
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ArticleEditorAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
}
/**
* 未登录访问
*/
@Order(1)
@Test
void notLogin() {
driver.get("http://120.25.124.200:7070/blog_editor.html");
}
/**
* 进行正确登录
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"admin,admin"})
@Order(2)
void loginSuccess(String username,String password) {
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
}
/**
* 正确登录场景下打开
* 检测点文章标题输入框是否存在
*/
@Order(3)
@Test
void openArticleEditor() {
// 点击写博客链接
driver.findElement(By.cssSelector("body > div.nav > span.links > a:nth-child(2)"));
// 直接输入url
driver.get("http://120.25.124.200:7070/blog_editor.html");
driver.manage().window().maximize();
// 检测页面是否正确打开
driver.findElement(By.cssSelector("#title"));
}
/**
* 错误发布示例
* @param title
* @throws InterruptedException
*/
@ParameterizedTest
@CsvSource({"null"})
@Order(4)
void postFail(String title) throws InterruptedException {
if (!"null".equals(title)) {
driver.findElement(By.cssSelector("#title")).sendKeys(title);
}
driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();
Thread.sleep(800);
Alert alert = driver.switchTo().alert();
alert.accept();
}
@ParameterizedTest
@CsvSource({"博客标题"})
@Order(5)
void postSuccess(String title) throws InterruptedException {
driver.findElement(By.cssSelector("#title")).sendKeys(title);
driver.findElement(By.xpath("/html/body/div[2]/div[1]/button[1]")).click();
Thread.sleep(800);
Alert alert = driver.switchTo().alert();
alert.accept();
}
@AfterAll
static void quit() {
driver.quit();
}
}
自动化演示:
代码编写:
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class SetQuestionPasswordAutoTest {
private static ChromeDriver driver;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
}
/**
* 未登录状态下访问
*/
@Order(1)
@Test
void notLogin() {
driver.get("http://120.25.124.200:7070/set_questionPass.html");
driver.manage().window().maximize();
}
/**
* 进行正确登录进入到修改密码页面
* @param username
* @param password
*/
@ParameterizedTest
@CsvSource({"admin,admin"})
@Order(2)
void loginSuccess(String username,String password) throws InterruptedException {
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys(username);
driver.findElement(By.cssSelector("#password")).sendKeys(password);
driver.findElement(By.xpath("//*[@id=\"submit\"]")).click();
Thread.sleep(500);
driver.get("http://120.25.124.200:7070/set_questionPass.html");
}
/***
* 错误设置
* @param password
* @param answerOne
* @param answerTwo
* @param answerThree
* @throws InterruptedException
*/
@ParameterizedTest
@CsvSource({"null,one,two,three","test,one,two,null","test,one,null,three","test,null,two,three","test,one,two,three"})
@Order(3)
void setQuestionPassFail(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {
WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));
WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));
WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));
WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));
if (!"null".equals(password)) {
passElement.sendKeys(password);
}
if (!"null".equals(answerOne)) {
oneElement.sendKeys(answerOne);
}
if (!"null".equals(answerTwo)) {
twoElement.sendKeys(answerTwo);
}
if (!"null".equals(answerThree)) {
threeElement.sendKeys(answerThree);
}
// 获取Select问题标签
Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));
Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));
Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));
// 选取问题
selectOne.selectByIndex(1);
selectTwo.selectByIndex(1);
selectThree.selectByIndex(1);
//提交
driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();
// 点击弹窗确认按钮
Thread.sleep(500);
driver.switchTo().alert().accept();
// 清空输入框
passElement.clear();
oneElement.clear();
twoElement.clear();
threeElement.clear();
}
/***
* 正确设置
* @param password
* @param answerOne
* @param answerTwo
* @param answerThree
* @throws InterruptedException
*/
@ParameterizedTest
@CsvSource({"admin,one,two,three"})
@Order(3)
void setQuestionPassSuccess(String password,String answerOne,String answerTwo,String answerThree) throws InterruptedException {
WebElement passElement = driver.findElement(By.xpath("//*[@id=\"password\"]"));
WebElement oneElement = driver.findElement(By.cssSelector("#oneValue"));
WebElement twoElement = driver.findElement(By.xpath("//*[@id=\"twoValue\"]"));
WebElement threeElement = driver.findElement(By.xpath("//*[@id=\"threeValue\"]"));
// 填写密码和问题
passElement.sendKeys(password);
oneElement.sendKeys(answerOne);
twoElement.sendKeys(answerTwo);
threeElement.sendKeys(answerThree);
// 获取Select问题标签
Select selectOne = new Select(driver.findElement(By.xpath("//*[@id=\"one\"]")));
Select selectTwo = new Select(driver.findElement(By.xpath("//*[@id=\"two\"]")));
Select selectThree = new Select(driver.findElement(By.xpath("//*[@id=\"three\"]")));
// 选取问题
selectOne.selectByIndex(1);
selectTwo.selectByIndex(1);
selectThree.selectByIndex(1);
//提交
driver.findElement(By.xpath("//*[@id=\"reg_submit\"]")).click();
}
/**
* 检测问题是否设置成功
*/
@Test
@Order(4)
void checkSetQuestion() throws InterruptedException {
driver.get("http://120.25.124.200:7070/find_pass.html");
Thread.sleep(1000);
driver.switchTo().alert().accept();
System.out.println(driver.getCurrentUrl());
driver.findElement(By.xpath("//*[@id=\"username\"]")).sendKeys("admin");
driver.findElement(By.cssSelector("#reg > div:nth-child(1) > button")).click();
String answer = driver.findElement(By.xpath("//*[@id=\"one\"]")).getText();
System.out.println(answer);
// 如果获取到了问题说明设置密保问题就成功了
Assertions.assertNotEquals("问题1",answer);
}
@AfterAll
static void quit() {
driver.quit();
}
}
自动化演示:
设置获取的密保问题的断言执行了。
在执行多次设置密保问后都设置成功了,但是在验证通过密保问题找回密码时,发生了错误。
通过查看数据库的问题表发现了问题:
同一个用户有多个问题存在数据表中,原因是设置密保问题时没有对已经设置过密保的用户进行校验。导致多次插入数据,引发查询到多条数据。
在测试过程中发现为找到过期元素异常
发现是每次点击上一页或者下一页,页面都会刷新,所以导致元素失效,原理的代码如下
@Test
void test() throws InterruptedException {
WebElement first = driver.findElement(By.cssSelector("body > div:nth-child(3) > div > button.first"));
WebElement last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));
WebElement front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));
WebElement next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));
first.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
front.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
next.click();
Thread.sleep(1000);
front.click();
Thread.sleep(1000);
last.click();
Thread.sleep(1000);
next.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
last.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
}
改进代码,每次切换页面后重新获取元素
public class BlogListAutoTest {
private static ChromeDriver driver;
static WebElement first;
static WebElement last;
static WebElement front;
static WebElement next;
@BeforeAll
static void init() {
driver = AutoTestUtil.getDriver();
driver.get("http://120.25.124.200:7070/blog_list.html");
driver.manage().window().maximize();
}
void get() {
first = driver.findElement(By.xpath("/html/body/div[3]/div/button[1]"));
last = driver.findElement(By.xpath("/html/body/div[3]/div/button[4]"));
front = driver.findElement(By.xpath("/html/body/div[3]/div/button[2]"));
next = driver.findElement(By.xpath("/html/body/div[3]/div/button[3]"));
}
@Test
void test() throws InterruptedException {
get();
first.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
front.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
next.click();
get();
Thread.sleep(1000);
front.click();
get();
Thread.sleep(1000);
last.click();
get();
Thread.sleep(1000);
next.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
get();
last.click();
Thread.sleep(1000);
driver.switchTo().alert().accept();
}
@AfterAll
static void quit() {
driver.quit();
}
}
自动化演示:
通过Junit5单元测试工具配合selenium4自动化工具有如下亮点(好处)
使用LoadRunner对项目做一个简单的性能测试,性能测试在本机上进行测试,测试云服务器太麻烦。
登录和所有文章列表页面是高频使用场景,通过LoadRunner模拟多个用户进行并发进行登录后访问所有文章列表页面。
Action()
{
//开启进入登录页事务
lr_start_transaction("login_index");
/* 注册获取返回参数,该方法可以配合打印返回数据,检测数据内容 */
web_reg_save_param("ParaResult",
"LB=",
"RB=",
LAST);
// 定时检查点,检测登录页面是否正确打开
web_reg_find("Text=登录",LAST);
// 定义虚拟用户结合点
lr_rendezvous("start");
// 进入登录页面
web_url("login_html",
"URL=http://127.0.0.1:7070/login.html",
"TargetFrame=",
"Resource=0",
"Referer=",
LAST);
// 结束进入登录页事务
lr_end_transaction("login_index", LR_AUTO);
//开启登录事务
lr_start_transaction("login");
// 进行登录
web_submit_data("login",
"Action=http://127.0.0.1:7070/user/login",
"Method=POST",
"EncType=application/x-www-form-urlencoded; charset=UTF-8",
"TargetFrame=",
"Referer=",
"Mode=HTTP",
ITEMDATA,
"Name=username", "Value=" , ENDITEM,
"Name=password", "Value=" , ENDITEM,
LAST);
//定时检测所有文章列表页检查点
web_reg_find("Text=查看全文",LAST);
// 结束登录事务
lr_end_transaction("login", LR_AUTO);
//文章列表事务
lr_start_transaction("blog_list");
// 登录后访问所有文章列表页面
web_url("blog_list",
"URL=http://127.0.0.1:7070/blog_list.html",
"TargetFrame=",
"Resource=0",
"Referer=",
LAST);
// 结束文章列表页事务
lr_end_transaction("blog_list", LR_AUTO);
return 0;
}
测试脚本没有问题后修改Action脚本的执行次数,执行5次脚本
为了保证测试的合理性,多个虚拟用户使用多个不同的账号进行登录,使用LoadRunner的参数化即可实现。
针对编写好的脚本通过Controller创建测试场景
3.设置每5秒进入3个虚拟用户到测试场景
4.设置虚拟用户执行循环执行5分钟
5.设置虚拟用户执行完毕后每10秒退出5个虚拟用户
6.添加监视系统资源
CPU运行时间和剩余内存
在事务报告中,一般只关注平均值和标准方差,标准偏差值越大,说明越不稳定。而且脚本里值是写3个事务,而这里却有6个,因为每个文件就是一个事务脚本文件中的(init、action、end)
通过虚拟用户运行图标发现,在脚本运行40秒到5分30秒之间虚拟用户给了服务器负载
通过点击率表可以看到和虚拟用户运行表运行对应起来,虚拟用户的增多点击率也随之增多,点击率越多说明和服务器的交互次数也越多。
吞吐量图形和点击数图形有点相似,但是吞吐量的曲线会稍后延后一点递增。因为吞吐量表示的是响应返回的资源数量,所有是要先有请求才会有响应。
通过事务响应时间发现,访问登录页面的时间比较长,登录事务时间响应时间是比较短的,(深蓝是访问登录页面、黄色是登录事务、粉红色是进入文章列表页面),在40秒的时候事务的响应时间达到最大,那个时候正是15个虚拟用户生成完成,进行访问服务,导致一大波请求到达服务,导致事务响应时间长。
虚拟用户在性能测试过程中,每秒在服务器上命中的次数,通过次图可以帮助根据命中次数评估虚拟用户生成的负载量