目录
一、前言及测试用例设计
二、 首页测试(未登录)
三、注册测试
四、对局列表测试
五、排行榜测试
六、对战测试
七、Bot测试
八、测试套件Suite
一、前言及测试用例设计
整个项目已经部署完成,我们历经九九八十一难,但再好的软件,bug也是再所难免,因此从这篇文章开始(也可能只有这一篇文章),我们就对整个项目进行测试,也会包含web自动化测试,因此如果没有学习过测试的同学可以看我之前的博客,废话不多说我们直接开始介绍我们的总体测试:
二、 首页测试(未登录)
首先在我们的test目录下新建 FrontPageTest 类,由于我们每次都要用到 Chrome 的驱动,因此我们可以把它封装成一个工具类:
package com.kob.backend.tests.common;
import org.openqa.selenium.chrome.ChromeDriver;
public class CommonDriver {
// 创建驱动对象并返回
private static ChromeDriver driver;
public ChromeDriver getDriver() {
if (driver == null) driver = new ChromeDriver();
return driver;
}
}
为了防止有时出现页面没加载出来的情况,这里添加隐式等待:
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(3000));
FrontPageTest:
package com.chaoyang.tests;
import com.chaoyang.autotest.common.CommonDriver;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
public class FrontPageTest {
private static ChromeDriver driver = CommonDriver.getDriver();
/*
跳转到对应url
*/
@BeforeAll
static void getUrl() {
driver.get("https://app2703.acapp.acwing.com.cn/");
}
/*
校验首页(未登录)是否正确展示元素
*/
@Test
void checkFunIsExist() {
String registerText = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li:nth-child(2) > a")).getText();
String loginText = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li:nth-child(1) > a")).getText();
// 检验文本是否符合预期
Assertions.assertEquals(registerText,"注册");
Assertions.assertEquals(loginText,"登录");
driver.quit();
}
}
三、注册测试
首先我们要保证我们的状态是未登录的,然后我们去校验“确认密码” 这个元素
@Test
void checkFunISExist() {
String registerText = driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > div:nth-child(3) > label")).getText();
// 获取注册页面是否包含对应文本,校验文本是否符合预期
Assertions.assertEquals(registerText,"确认密码");
}
如何确定我们从注册页面跳转到登录页面呢?我们去校验页面包含“密码”而不含“确认密码”即可,
void addUser() {
// 用户名
driver.findElement(By.cssSelector("#username")).sendKeys("杨过7");
// 密码
driver.findElement(By.cssSelector("#password")).sendKeys("123");
// 确认密码
driver.findElement(By.cssSelector("#confirmedPassword")).sendKeys("123");
// 提交
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
// 是否跳转到登录界面
// 包含输入密码 但 不包含 确认密码 即可确定我们已经到达登录界面
String password = driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > div:nth-child(2) > label")).getText();
Assertions.assertEquals(password,"密码");
}
但这样一次添加一个用户测试太慢,这时就要使用到我们的参数化,使用大量数据测试!
不了解参数化的朋友可以看我之前软件测试章节补补功课
添加@ParameterizedTest 注解
添加数据来源注解
这里可以构造一个static 同名方法即可
参数来源 common.ParamsUtil:
package com.chaoyang.tests.common;
public class ParamsUtil {
private String[] users = new String[] {"姜子牙1","瑞文1","鲁班八号","百里守约1","芈月1"};
private String[] password = new String[] {"123","321","456","qwer123","哈哈哈"};
public String getUserName() {
// 随机返回一个用户名
int index = (int)(Math.random()*users.length);
return users[index];
}
/*
密码和确认密码
*/
public String getPassword() {
int index = (int)(Math.random()*password.length);
return password[index];
}
}
RegisterTest:
package com.chaoyang.tests;
import com.chaoyang.autotest.common.CommonDriver;
import com.chaoyang.tests.common.ParamsUtil;
import org.junit.jupiter.api.*;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.stream.Stream;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class RegisterTest {
private static ChromeDriver driver = CommonDriver.getDriver();
/*
跳转url
*/
@BeforeAll
static void getUrl() {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/register/");
}
@Test
@Order(1)
void checkFunISExist() {
String registerText = driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > div:nth-child(3) > label")).getText();
// 获取注册页面是否包含对应文本,校验文本是否符合预期
Assertions.assertEquals(registerText,"确认密码");
}
/*
正确注册用户之后跳转到登录页面
*/
@Order(2)
@ParameterizedTest()
@MethodSource()
void addUser(String name,String password,String confirmedPassword) {
// 用户名
driver.findElement(By.cssSelector("#username")).sendKeys(name);
// 密码
driver.findElement(By.cssSelector("#password")).sendKeys(password);
// 确认密码
driver.findElement(By.cssSelector("#confirmedPassword")).sendKeys(confirmedPassword);
// 提交
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
// 是否跳转到登录界面
// 包含输入密码 但 不包含 确认密码 即可确定我们已经到达登录界面
String password1 = driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > div:nth-child(2) > label")).getText();
Assertions.assertEquals(password1,"密码");
}
static Stream<Arguments> addUser() {
// 给 addUSer 提供数据来源
ParamsUtil paramsUtil = new ParamsUtil();
String userName = paramsUtil.getUserName();
String password = paramsUtil.getPassword();
return Stream.of(Arguments.arguments(userName,password,password));
}
@AfterAll
static void driverQuit() {
// driver.quit();
}
}
测试结果:
成功跳转! 完美实现!
四、对局列表测试
当我们登录之后,测试我们是否可以正常获取所有的对局列表,以及是否可以正常查看回放,以及切页功能是否正常。
创建 RecordTest:
package com.chaoyang.tests;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
public class RecordTest {
private static ChromeDriver driver = new ChromeDriver();
/*
跳转到对局回顾 url
*/
@BeforeAll
static void getUrl() throws InterruptedException {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/login/");
driver.findElement(By.cssSelector("#username")).sendKeys("杨过1");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
Thread.sleep(1000);
driver.findElement(By.cssSelector("#navbarText > ul.navbar-nav.me-auto.mb-2.mb-lg-0 > li:nth-child(2) > a")).click();
}
/*
测试是否正确展示元素
*/
@Test
void checkFunIsExist() throws InterruptedException {
String A = driver.findElement(By.cssSelector("#app > div > div > div > table > thead > tr > th:nth-child(1)")).getText();
String B = driver.findElement(By.cssSelector("#app > div > div > div > table > thead > tr > th:nth-child(2)")).getText();
String recordTime = driver.findElement(By.cssSelector("#app > div > div > div > table > thead > tr > th:nth-child(4)")).getText();
Assertions.assertEquals(A,"A");
Assertions.assertEquals(B,"B");
Assertions.assertEquals(recordTime,"对战时间");
driver.findElement(By.cssSelector("#app > div > div > div > table > tbody > tr:nth-child(2) > td:nth-child(5) > button")).click();
// 点击之后等待四秒,保证我们的对局回放结束
Thread.sleep(4000);
}
@AfterAll
static void driverQuit() {
driver.quit();
}
}
同时在每一次断言前截图,方便我们留存
CommonDriver中修改:
package com.chaoyang.tests.common;
import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.chrome.ChromeDriver;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public class CommonDriver {
// 创建驱动对象并返回
private static ChromeDriver driver;
public static ChromeDriver getDriver() {
if (driver == null) {
driver = new ChromeDriver();
// 添加隐式等待
// selenium 是无法等待弹窗的 如果遇到弹窗 可以强制等待
driver.manage().timeouts().implicitlyWait(Duration.ofMillis(3000));
}
return driver;
}
public static List<String> getTime() {
// 文件名格式 20221201-141030+毫秒
SimpleDateFormat sim1 = new SimpleDateFormat("yyyyMMdd-HHmmssSS");
// 文件夹名称格式 2022-12-01
SimpleDateFormat sim2 = new SimpleDateFormat("yyyy-MM-dd");
String filename = sim1.format(System.currentTimeMillis());
String dirname = sim2.format(System.currentTimeMillis());
List<String> list = new ArrayList<>();
list.add(dirname);
list.add(filename);
return list;
}
/*
获取屏幕截图
str:类名下的用例
*/
public static void getScreenshot(String str) throws IOException {
List<String> times = getTime();
String filename = "./src/test/autotest-" + times.get(0) + "/" + str + "-" + times.get(1) + ".png";
File srcFile = driver.getScreenshotAs(OutputType.FILE);
// 把截图放到指定路径下
FileUtils.copyFile(srcFile,new File(filename));
}
}
测试上下切页功能是否正常
/*
测试切换页面功能
*/
@Test
void checkChange() throws InterruptedException {
for (int i = 0; i < 3; i ++) {
driver.findElement(By.cssSelector("#app > div > div > div > nav > ul > li:nth-child(5) > a")).click();
Thread.sleep(1000);
}
}
五、排行榜测试
进入排行榜页面之后,我们可以得到所有用户的 rating 分和 用户名 ,在次基础上我们开始测试排行榜是否能正确展示以及上下切换功能是否正常
RankListTest:
package com.chaoyang.tests;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
public class RankListTest {
private static ChromeDriver driver = new ChromeDriver();
/*
跳转到排行榜 url
*/
@BeforeAll
static void getUrl() throws InterruptedException {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/login/");
driver.findElement(By.cssSelector("#username")).sendKeys("杨过1");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
Thread.sleep(1000);
driver.findElement(By.cssSelector("#navbarText > ul.navbar-nav.me-auto.mb-2.mb-lg-0 > li:nth-child(3) > a")).click();
}
/*
测试是否正确展示元素
*/
@Test
void checkFunIsExist() throws InterruptedException {
String player = driver.findElement(By.cssSelector("#app > div > div > div > table > thead > tr > th:nth-child(1)")).getText();
String rating = driver.findElement(By.cssSelector("#app > div > div > div > table > thead > tr > th:nth-child(2)")).getText();
Assertions.assertEquals(player,"玩家");
Assertions.assertEquals(rating,"天梯分");
}
/*
测试切换页面功能
*/
@Test
void checkChange() throws InterruptedException {
for (int i = 0; i < 3; i ++) {
driver.findElement(By.cssSelector("#app > div > div > div > nav > ul > li:nth-child(5) > a")).click();
Thread.sleep(1000);
}
}
}
六、Bot测试
当我们的用户处于登录状态时,我们可以通过点击自己的用户名进而创建 Bot 或删除 Bot
接下来我们就对于Bot的创建删除等功能进行测试:
切换页面功能:
创建Bot功能:
package com.chaoyang.tests;
import com.chaoyang.tests.common.CommonDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BotTest {
private static ChromeDriver driver = CommonDriver.getDriver();
/*
跳转到排行榜 url
*/
@BeforeAll
static void getUrl() throws InterruptedException {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/login/");
driver.findElement(By.cssSelector("#username")).sendKeys("杨过1");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
Thread.sleep(1000);
driver.findElement(By.cssSelector("#navbarDropdown")).click();
}
/*
测试是否正确展示元素
*/
@Test
@Order(1)
void checkFunIsExist() throws InterruptedException {
String bot = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(1) > a")).getText();
String exit = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(3) > a")).getText();
Assertions.assertEquals(bot,"我的Bot");
Assertions.assertEquals(exit,"退出");
}
/*
测试切换页面功能 - 到Bot页面
*/
@Test
@Order(2)
void checkChange() throws InterruptedException {
driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(1) > a")).click();
String myBot = driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-header > span")).getText();
Assertions.assertEquals(myBot,"我的Bot");
}
/*
创建Bot 功能
*/
@Test
@Order(3)
void checkCreateBot() {
driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-header > button")).click();
// 输入名称,简介,代码等。。。。
driver.findElement(By.cssSelector("#add-bot-title")).sendKeys("名称1");
driver.findElement(By.cssSelector("#add-bot-description")).sendKeys("简介1");
driver.findElement(By.cssSelector("#add-bot-btn > div > div > div.modal-footer > button.btn.btn-primary")).click();
}
}
修改Bot功能:
删除Bot功能:
成功删除~
package com.chaoyang.tests;
import com.chaoyang.tests.common.CommonDriver;
import org.junit.jupiter.api.*;
import org.openqa.selenium.Alert;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class BotTest {
private static ChromeDriver driver = CommonDriver.getDriver();
/*
跳转到排行榜 url
*/
@BeforeAll
static void getUrl() throws InterruptedException {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/login/");
driver.findElement(By.cssSelector("#username")).sendKeys("杨过1");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
Thread.sleep(1000);
driver.findElement(By.cssSelector("#navbarDropdown")).click();
}
/*
测试是否正确展示元素
*/
@Test
@Order(1)
void checkFunIsExist() throws InterruptedException {
String bot = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(1) > a")).getText();
String exit = driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(3) > a")).getText();
Assertions.assertEquals(bot,"我的Bot");
Assertions.assertEquals(exit,"退出");
}
/*
测试切换页面功能 - 到Bot页面
*/
@Test
@Order(2)
void checkChange() throws InterruptedException {
driver.findElement(By.cssSelector("#navbarText > ul:nth-child(2) > li > ul > li:nth-child(1) > a")).click();
String myBot = driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-header > span")).getText();
Assertions.assertEquals(myBot,"我的Bot");
}
/*
创建Bot 功能
*/
@Test
@Order(3)
void checkCreateBot() {
driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-header > button")).click();
// 输入名称,简介,代码等。。。。
driver.findElement(By.cssSelector("#add-bot-title")).sendKeys("名称1");
driver.findElement(By.cssSelector("#add-bot-description")).sendKeys("简介1");
driver.findElement(By.cssSelector("#add-bot-btn > div > div > div.modal-footer > button.btn.btn-primary")).click();
driver.findElement(By.cssSelector("#add-bot-btn > div > div > div.modal-footer > button.btn.btn-secondary")).click();
Alert alert = driver.switchTo().alert();
alert.dismiss();
}
@Test
@Order(4)
void checkUpdate() {
driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-body > table > tbody > tr > td:nth-child(3) > button.btn.btn-secondary")).click();
driver.findElement(By.cssSelector("#add-bot-title")).sendKeys("名称1");
driver.findElement(By.cssSelector("#add-bot-description")).sendKeys("简介1");
driver.findElement(By.cssSelector("#add-bot-btn > div > div > div.modal-footer > button.btn.btn-primary")).click();
driver.findElement(By.cssSelector("#add-bot-btn > div > div > div.modal-footer > button.btn.btn-secondary")).click();
}
@Test
@Order(5)
void checkDelete() {
driver.findElement(By.cssSelector("#app > div > div > div.col-9 > div > div.card-body > table > tbody > tr > td:nth-child(3) > button.btn.btn-danger")).click();
}
}
七、对战测试
当我们进入到对战页面后,我们可以开始匹配进入游戏,也可以选择让我们的代码替我们出战,此时我们需要测试软件是否能正确展示我们的Bot并且可以选择人或者bot 出战!
展示测试:
下拉框测试(Bot列表):
开始匹配功能测试:
package com.chaoyang.tests;
import com.chaoyang.tests.common.CommonDriver;
import org.junit.jupiter.api.*;
import org.junit.platform.suite.api.SelectClasses;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.Select;
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class PkTest {
private static ChromeDriver driver = CommonDriver.getDriver();
/*
跳转到pk url (首页默认就是pk)
*/
@BeforeAll
static void getUrl() throws InterruptedException {
driver.get("https://app2703.acapp.acwing.com.cn/user/account/login/");
driver.findElement(By.cssSelector("#username")).sendKeys("杨过1");
driver.findElement(By.cssSelector("#password")).sendKeys("123");
driver.findElement(By.cssSelector("#app > div > div > div > div > div > form > button")).click();
}
/*
测试是否正确展示元素
*/
@Test
@Order(1)
void checkFunIsExist() throws InterruptedException {
String pk = driver.findElement(By.cssSelector("#app > div > div > div.col-12 > button")).getText();
Assertions.assertEquals(pk,"开始匹配");
}
/*
测试切换bot功能
*/
@Test
@Order(2)
void checkChange() throws InterruptedException {
WebElement ele = driver.findElement(By.cssSelector("#app > div > div > div:nth-child(2) > div > select"));
Select select = new Select(ele);
select.selectByIndex(0);
}
/*
测试开始匹配功能
*/
@Test
@Order(3)
void checkPK() {
driver.findElement(By.cssSelector("#app > div > div > div.col-12 > button")).click();
}
}
八、测试套件Suite
一个一个测试很麻烦,我们把所有的测试类集成到一个类RunSuite中:
删除我们之前每个类中的driver.quit()
因此我们把这个driver.quit专门抽取为一个类,放在最后执行即可
package com.chaoyang.tests;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
@Suite
@SelectClasses({FrontPageTest.class,RegisterTest.class,RecordTest.class,DriverQuitTest.class})
public class RunSuite {
}
截图成功!