目录
一、项目的介绍
本项目是基于 Spring 开发的前后端分离的网页五子棋游戏。
在该项目的开发中使用到 SpringBoot 构建项目基础框架 、SpringMVC 开发 Web 应用程序 及 Mybatis 来操作数据库,WebSocket 来实时通信实现消息推送机制等。
二、项目功能
本项目实现了登录,注册,玩家匹配 (根据天梯积分匹配) ,玩家对弈,防止多开,记录胜利场次,管理天梯积分等功能。
登录界面:
注册界面:
游戏大厅:
游戏房间:
玩家对弈:
三、测试项目
1.编写测试用例

2.执行部分测试用例
登录界面测试:
1)输入正确的用户名与密码 -- 登录成功进入首页
2)输入错误的用户名 -- 提示用户名不存在
3)输入错误的密码 -- 提示密码错误
4)登录已经在线的用户 -- 提示账号在别处登录
注册界面:
1)输入基本的注册信息 -- 提示注册成功并跳转登录界面
2)输入存在的用户名 -- 提示用户名已存在
游戏大厅:
点击匹配 -- 开始匹配(提示匹配中)
游戏房间 :
1)点击棋盘 -- 在对应位置落子(落子后提示对方落子)
2)轮到对方落子自己点击棋盘 -- 点击无效
3)游戏结束 -- 显示胜负
4)对手掉线 -- 提示掉线并获胜
3.自动化测试
1)添加相关Maven依赖(pom.xml)
<dependencies>
<!-- 用来自动下载浏览器驱动 -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.8.0</version>
<scope>test</scope>
</dependency>
<!-- 用来自动化Web浏览器操作 -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.0.0</version>
</dependency>
<!-- 用来使用屏幕截图操作 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
2)编写界面测试用例

3)编写自动化代码测试部分测试用例
Utils类:
用来定义不同页面测试所用到的公共属性(例如:浏览器驱动),定义一些公共方法,(例如:屏幕截图,创建浏览器驱动)package common; import io.github.bonigarcia.wdm.WebDriverManager; import org.apache.commons.io.FileUtils; import org.openqa.selenium.OutputType; import org.openqa.selenium.TakesScreenshot; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.support.ui.WebDriverWait; import java.io.File; import java.io.IOException; import java.text.SimpleDateFormat; import java.time.Duration; public class Utils { // 定义浏览器驱动 public static WebDriver driver = null; public WebDriverWait wait = null; public Utils(String url) { //调用driver对象 driver = createDriver(); // 显示等待 wait = new WebDriverWait(driver, Duration.ofSeconds(2)); // 浏览器跳转到 URL 界面 driver.get(url); } // 创建浏览器驱动 private 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(3)); } return driver; } // 屏幕截图 public void screenshot(String str,String describe) throws IOException { // 根据年月日创建文件夹 SimpleDateFormat sim1 = new SimpleDateFormat("yyyy-MM-dd"); // 根据时分秒时间戳命名图片 SimpleDateFormat sim2 = new SimpleDateFormat("HHmmssSS"); String dirTime = sim1.format(System.currentTimeMillis()); String fileTime = sim2.format(System.currentTimeMillis()); // ./src/test/java/images/2025-04-14/test01/描述13972011.png String filename = "./src/test/java/images/"+ dirTime + "/" + str + "/" + describe +fileTime + ".png"; File image = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(image,new File(filename)); } }
LoginTest类:
用来自动化测试登录界面package tests; import common.Utils; import org.openqa.selenium.Alert; import org.openqa.selenium.By; import org.openqa.selenium.support.ui.ExpectedConditions; import java.io.IOException; // 自动化测试登录界面 继承 Utils 类就能使用 Utils 创建好的浏览器驱动和一些公共方法 public class LoginTest extends Utils { // 登录界面的URL private static String url = "http://127.0.0.1:8080/gobang_login.html"; public LoginTest() { super(url); } // 检查元素是否存在 -- 不存在就报错 public void checkEleExist() { // 检查用户名输入框是否存在 driver.findElement(By.cssSelector("#username")); // 检查密码输入框是否存在 driver.findElement(By.cssSelector("#password")); // 检查登录按钮是否存在 driver.findElement(By.cssSelector("#submit")); // 检查点击注册是否存在 driver.findElement(By.cssSelector("body > div.container-login > div > div:nth-child(5) > a")); // 检查图标是否存在 driver.findElement(By.cssSelector("body > div.nav > img")); } // 登录成功测试 public void checkLoginSuccess() throws IOException { // 先清空输入框 防止有信息遗留在输入框上 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys("ml"); driver.findElement(By.cssSelector("#password")).sendKeys("ml"); driver.findElement(By.cssSelector("#submit")).click(); // 登录成功跳转游戏大厅,检查匹配按钮是否存在 存在 -- 登录成功 // 不存在 -- 报错 driver.findElement(By.cssSelector("#match-button")); } // 登录失败测试 public void LoginFail() throws InterruptedException { //先清空输入框 防止有信息遗留在输入框上 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); // 1. 不输入用户名 driver.findElement(By.cssSelector("#username")).sendKeys(""); driver.findElement(By.cssSelector("#password")).sendKeys("123456"); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗出现 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 Alert alert = driver.switchTo().alert(); // 获取弹窗信息 String text = alert.getText(); // 要是获取的提示不正确报错 assert "用户不存在".equals(text); // 处理弹窗 alert.accept(); // 2. 输入不存在的用户名 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys("mmm"); driver.findElement(By.cssSelector("#password")).sendKeys("123456"); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗出现 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 alert = driver.switchTo().alert(); text = alert.getText(); // 要是获取的提示不正确报错 assert "用户不存在".equals(text); // 处理弹窗 alert.accept(); // 3. 输入错误的密码 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys("ml"); driver.findElement(By.cssSelector("#password")).sendKeys("666"); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗出现 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 alert = driver.switchTo().alert(); text = alert.getText(); // 要是获取的提示不正确报错 assert "密码错误".equals(text); // 处理弹窗 alert.accept(); } }
RegisterTest类:
用来自动化测试注册界面package tests; import common.Utils; import org.openqa.selenium.Alert; import org.openqa.selenium.By; import org.openqa.selenium.support.ui.ExpectedConditions; import java.util.UUID; public class RegisterTest extends Utils { // 注册界面的URL private static String url = "http://127.0.0.1:8080/gobang_register.html"; public RegisterTest() { super(url); } // 检查元素是否存在 -- 不存在就报错 public void checkEleExist() { // 检查用户名输入框是否存在 driver.findElement(By.cssSelector("#username")); driver.findElement(By.cssSelector("#password")); // 检查注册按钮是否存在 driver.findElement(By.cssSelector("#submit")); // 检查图标是否存在 driver.findElement(By.cssSelector("body > div.nav > img")); // 检查游戏名是否存在 driver.findElement(By.cssSelector("body > div.nav > span")); } // 测试注册成功 public void checkRegisterSuccess() { // 先清除输入框内容 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); // 获取随机字符串,避免用户名重复 String userName = getUserName(); // 输入正确的用户名,昵称,密码与确认密码,勾选同意使用条款能否注册成功 driver.findElement(By.cssSelector("#username")).sendKeys(userName); driver.findElement(By.cssSelector("#password")).sendKeys("123456"); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 Alert alert = driver.switchTo().alert(); // 获取弹窗信息 String text = alert.getText(); // 要是获取的提示不正确报错 assert "注册成功".equals(text); // 处理弹窗 alert.accept(); } // 测试注册失败 public void checkRegisterFail() { // 1. 注册用户名存在的用户 // 先清除输入框内容 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); // 注册用户名存在的用户 driver.findElement(By.cssSelector("#username")).sendKeys("ml"); driver.findElement(By.cssSelector("#password")).sendKeys("123456"); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 Alert alert = driver.switchTo().alert(); // 获取弹窗信息 String text = alert.getText(); // 要是获取的提示不正确报错 assert "用户名已存在".equals(text); // 处理弹窗 alert.accept(); // 2. 不填写密码和用户名 // 先清除输入框内容 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys(""); driver.findElement(By.cssSelector("#password")).sendKeys(""); driver.findElement(By.cssSelector("#submit")).click(); // 显示等待弹窗 wait.until(ExpectedConditions.alertIsPresent()); // 获取弹窗 alert = driver.switchTo().alert(); // 获取弹窗信息 text = alert.getText(); // 要是获取的提示不正确报错 assert "用户名或密码为空".equals(text); // 处理弹窗 alert.accept(); } // 获取随机用户名 private String getUserName() { UUID uuid = UUID.randomUUID(); String username = String.valueOf(uuid); username = username.substring(1,8); return username; } }
GameHallTest类:
用来测试游戏大厅界面package tests; import common.Utils; import org.openqa.selenium.By; public class GameHallTest extends Utils { // 游戏大厅界面的URL private static String url = "http://127.0.0.1:8080/game_hall.html"; public GameHallTest() { super(url); } // 检查元素是否存在 -- 不存在就报错 public void checkEleExist() { // 检查开始匹配按钮是否存在 driver.findElement(By.cssSelector("#match-button")); // 检查信息是否显示 driver.findElement(By.cssSelector("#screen")); // 检查图标是否存在 driver.findElement(By.cssSelector("body > div.nav > img")); // 检查游戏名是否存在 driver.findElement(By.cssSelector("body > div.nav > span")); } public void checkMatch() { // 检查开始匹配按钮是否存在 String text = driver.findElement(By.cssSelector("#match-button")).getText(); // 要是获取的文本与预期不符不正确报错 assert "开始匹配".equals(text); // 点击按钮看是否开始匹配 driver.findElement(By.cssSelector("#match-button")).click(); // 点击后按钮文本会改变 text = driver.findElement(By.cssSelector("#match-button")).getText(); // 要是获取的文本与预期不符不正确报错 assert "匹配中...(点击停止)".equals(text); // 再次点击按钮看是否停止匹配 driver.findElement(By.cssSelector("#match-button")).click(); // 点击后按钮文本会改变 text = driver.findElement(By.cssSelector("#match-button")).getText(); // 要是获取的文本与预期不符不正确报错 assert "开始匹配".equals(text); } }
GameRoomTest类:
用来测试游戏房间界面package tests; import io.github.bonigarcia.wdm.WebDriverManager; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.chrome.ChromeOptions; import org.openqa.selenium.edge.EdgeDriver; import org.openqa.selenium.edge.EdgeOptions; import org.openqa.selenium.support.ui.WebDriverWait; import java.time.Duration; public class GameRoomTest { // 登录界面的URL -- 一般是从登录 --> 游戏大厅 --> 游戏房间 private static String loginUrl = "http://127.0.0.1:8080/game_room.html"; // 不能直接进入游戏房间要匹配,测试 // 游戏房间界面的URL private static String gameRoomUrl = "http://127.0.0.1:8080/game_room.html"; private WebDriver chromeDriver = null; private WebDriver edgeDriver = null; private WebDriverWait chromeWait = null; private WebDriverWait edgeWait = null; // 构造方法一进来就创建驱动 public GameRoomTest() { createChromeDriver(); createEdgeDriver(); } // 创建 chrome 浏览器驱动 private void createChromeDriver() { //下载驱动 WebDriverManager.chromedriver().setup(); ChromeOptions options = new ChromeOptions(); //允许访问所有的链接 options.addArguments("--remote-allow-origins=*"); chromeDriver = new ChromeDriver(options); //隐式等待 chromeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3)); chromeWait = new WebDriverWait(chromeDriver, Duration.ofSeconds(2)); chromeDriver.get(loginUrl); } // 创建 edge 浏览器驱动 private void createEdgeDriver() { //下载驱动 WebDriverManager.edgedriver().setup(); EdgeOptions options = new EdgeOptions(); //允许访问所有的链接 options.addArguments("--remote-allow-origins=*"); edgeDriver = new EdgeDriver(options); //隐式等待 edgeDriver.manage().timeouts().implicitlyWait(Duration.ofSeconds(3)); edgeWait = new WebDriverWait(edgeDriver, Duration.ofSeconds(2)); edgeDriver.get(loginUrl); } // 登录操作 private void login(WebDriver driver, String userName,String password) { // 先清空输入框 防止有信息遗留在输入框上 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys(userName); driver.findElement(By.cssSelector("#password")).sendKeys(password); driver.findElement(By.cssSelector("#submit")).click(); } // 执行 js 代码在棋盘上落子 private void chess(int row,int col,WebDriver driver) { int x = 15 + col * 30; // 计算 X 坐标 int y = 15 + row * 30; // 计算 Y 坐标 String clickScript = "var canvas = document.querySelector('#chess'); " + "var rect = canvas.getBoundingClientRect(); " + "var x = rect.left + " + x + "; " + "var y = rect.top + " + y + "; " + "var clickEvent = new MouseEvent('click', { " + " clientX: x, " + " clientY: y " + "}); " + "canvas.dispatchEvent(clickEvent);"; ((JavascriptExecutor) driver).executeScript(clickScript); } // 检查能否正常进入房间 public void checkIntoRoom() { // 1. 先给两个浏览器登录 login(chromeDriver,"lisi","123"); login(edgeDriver,"zhangsan","123"); // 2. 双方点击匹配进入房间 // 点击按钮开始匹配 chromeDriver.findElement(By.cssSelector("#match-button")).click(); edgeDriver.findElement(By.cssSelector("#match-button")).click(); } // 检查元素是否存在 -- 不存在就报错 public void checkPlayChess() throws InterruptedException { // 检查棋盘 chromeDriver.findElement(By.cssSelector("#chess")); // 检查图标是否存在 chromeDriver.findElement(By.cssSelector("body > div.nav > img")); // 检查游戏名是否存在 chromeDriver.findElement(By.cssSelector("body > div.nav > span")); // c 在棋盘 (1,1) 位置落子 chess(1,1,chromeDriver); // e 在棋盘 (2,1) 位置落子 chess(2,1,edgeDriver); // c 在棋盘 (1,2) 位置落子 chess(1,2,chromeDriver); // e 在棋盘 (2,2) 位置落子 chess(2,2,edgeDriver); // c 在棋盘 (1,3) 位置落子 chess(1,3,chromeDriver); // e 在棋盘 (2,3) 位置落子 chess(2,3,edgeDriver); // c 在棋盘 (1,4) 位置落子 chess(1,4,chromeDriver); // e 在棋盘 (2,4) 位置落子 chess(2,4,edgeDriver); // c 在棋盘 (1,5) 位置落子 chess(1,5,chromeDriver); // c 获胜检查是否提示胜出 String text = chromeDriver.findElement(By.cssSelector("#screen")).getText(); // 检查是否与预期结果匹配 assert "你赢了!".equals(text); // 返回游戏大厅 chromeDriver.findElement(By.cssSelector("body > div.container > div > button")).click(); edgeDriver.findElement(By.cssSelector("body > div.container > div > button")).click(); } // 检查玩家掉线 public void checkUserLost() throws InterruptedException { // 点击按钮开始匹配 进入游戏房间 chromeDriver.findElement(By.cssSelector("#match-button")).click(); edgeDriver.findElement(By.cssSelector("#match-button")).click(); // 强制等待 2s 让玩家匹配成功 Thread.sleep(2000); // 关闭浏览器模拟掉线 edgeDriver.quit(); // 查看是否提示获胜 String text = chromeDriver.findElement(By.cssSelector("#screen")).getText(); // 检查是否与预期结果匹配 assert "对方掉线,你赢了!".equals(text); } }
















4710

被折叠的 条评论
为什么被折叠?



