网页版五子棋对战实现和自动化测试

网页版五子棋对战实现和自动化测试五子棋对战网页应用是一个基于 Web 技术的在线多人五子棋游戏

大家好,欢迎来到IT知识分享网。


前言

五子棋对战网页应用是一个基于Web技术的在线多人五子棋游戏。该应用提供了用户注册、登录、匹配对手、对战等功能,旨在为用户提供轻松愉快的游戏体验。本篇文章主要用来记录我的网页版五子棋项目,包括项目介绍、实现功能、测试用例、自动化测试等。


一、项目描述

该项目支持玩家随时随地与其他在线玩家进行五子棋对战,实现实时的棋局同步和即时通讯。利用 WebSocket 技术实现双向通信,保证游戏过程中的实时性和即时交互,提供更流畅的游戏体验。 提供游戏大厅,展示在线玩家信息、排名和当前对局状态。内置匹配系统,自动匹配合适的对手,确保玩家能够享受到公平有趣的游戏。

项目演示链接

二、实现的功能与操作

现在已实现注册登录功能、游戏匹配功能、下棋功能。

1.登录注册

 @RequestMapping("/login") public Object login(HttpServletRequest request, String username, String password) { 
      // 1.从数据库中找到匹配用户 User user = userMapper.selectByName(username); System.out.println("当前登录用户:user=" + user); if (user == null || !user.getPassword().equals(password)) { 
      // 登录失败 System.out.println("登录失败!"); return new User(); } HttpSession httpSession = request.getSession(true); httpSession.setAttribute("user", user); return user; } @RequestMapping("/register") public Object register(String username, String password) { 
      try { 
      User user = new User(); user.setUsername(username); user.setPassword(password); userMapper.insert(user); return user; } catch (org.springframework.dao.DuplicateKeyException e) { 
      User user = new User(); return user; } } 

注册前端代码(示例):

 <script> function mysub() { 
      var username = jQuery("#username"); var password = jQuery("#password"); var password2 = jQuery("#password2"); if(username.val()=="") { 
      alert("请先输入用户名!"); username.focus(); return; } if(password.val()=="") { 
      alert("请先输入密码!"); password.focus(); return; } if(password2.val()=="") { 
      alert("请确认密码!"); password2.focus(); return; } if(password2.val()!=password.val()) { 
      alert("两次密码输入不一致!"); password.focus(); return; } jQuery.ajax({ 
      url:"/user/register", type:"POST", data:{ 
     "username":username.val(),"password":password.val()}, success:function(result) { 
      if(result && result.username) { 
      if(confirm("恭喜:注册成功,是否跳转到登录页面?")) { 
      location.href = "/login.html"; } }else { 
      alert("抱歉:注册失败,请重试!"); } } }); } </script> 

2.游戏大厅

游戏匹配后端代码如下(示例):

 // 建立连接之后 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { 
      // 玩家上线,加入到onlineUserManager try { 
      //1.先获取当前用户的身份信息 // webSocketSession通过addInterceptors获取httpsession中的Attributes User user = (User) session.getAttributes().get("user"); //2.判定当前用户是否是已经在线状态 if (onlineUserManager.getFromGameHall(user.getUserId()) != null || onlineUserManager.getFromGameRoom(user.getUserId()) != null) { 
      //说明当前用户已经登录! //告知客户端重复登录 MatchResponse response = new MatchResponse(); response.setOk(true); response.setReason("当前禁止多开!"); response.setMessage("repeatConnection"); session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response))); // 直接关闭有些太激进 //session.close(); return; } //3.将玩家设置为在线状态 onlineUserManager.enterGameHall(user.getUserId(), session); System.out.println("玩家:" + user.getUsername() + " 进入游戏大厅!"); } catch (NullPointerException e) { 
      System.out.println("[MatchAPI.afterConnectionEstablished]当前用户未登录"); } } // 处理传输信息 @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 
      // 处理开始匹配请求和处理停止匹配请求 User user = (User) session.getAttributes().get("user"); // 获取客户端发送给服务器的数据 String payload = message.getPayload(); // 将JSON搁置的字符串,转换为对象 MatchRequest request = objectMapper.readValue(payload, MatchRequest.class); MatchResponse response = new MatchResponse(); if (request.getMessage().equals("startMatch")) { 
      //(1)进入匹配队列 //(2)创建一个类表示匹配队列,把当前用户加进去 matcher.add(user); response.setOk(true); response.setMessage("startMatch"); } else if (request.getMessage().equals("stopMatch")) { 
      // (1)退出匹配队列 // (2)创建一个类表示匹配队列,把当前用户从队列中移除 matcher.remove(user); // 移除之后,返回一个响应给客户端 response.setOk(true); response.setMessage("stopMatch"); } else { 
      // 非法情况 response.setOk(false); response.setReason("非法的匹配请求"); } String jsonString = objectMapper.writeValueAsString(response); session.sendMessage(new TextMessage(jsonString)); } // 处理传输异常 @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { 
      // 玩家下线,从 onlineUserManager 中删除 try { 
      User user = (User) session.getAttributes().get("user"); WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId()); // 保证退出的人和登录的人是一个人 if (tmpSession == session) { 
      onlineUserManager.exitGameHall(user.getUserId()); System.out.println("玩家:" + user.getUsername() + " 退出游戏大厅!"); } // 如果玩家正在匹配中,而 websocket 连接断开 matcher.remove(user); } catch (NullPointerException e) { 
      System.out.println("[MatchAPI.handleTransportError]当前用户未登录"); } } // 处理传输关闭 @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { 
      try { 
      // 玩家下线,从 onlineUserManager 中删除 User user = (User) session.getAttributes().get("user"); WebSocketSession tmpSession = onlineUserManager.getFromGameHall(user.getUserId()); // 保证退出的人和登录的人是一个人 if (tmpSession == session) { 
      onlineUserManager.exitGameHall(user.getUserId()); System.out.println("玩家:" + user.getUsername() + " 退出游戏大厅!"); } // 如果玩家正在匹配中,而 websocket 连接断开 matcher.remove(user); } catch (NullPointerException e) { 
      System.out.println("[MatchAPI.afterConnectionClosed]当前用户未登录"); } } 

线程安全问题

多开处理

3.五子棋对战

Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { 
      GameReadyResponse response = new GameReadyResponse(); // 1.先获取到用户的身份信息,(从httpsession中拿到当前用户的对象) User user = (User) session.getAttributes().get("user"); if (user == null) { 
      response.setOk(false); response.setReason("用户尚未登录!"); session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response))); return; } // 2.判断当前用户是否已经进入房间 Room room = roomManager.getRoomByUserId(user.getUserId()); if (room == null) { 
      // 该玩家还没有匹配到对手,不应该进入房间 response.setOk(false); response.setReason("用户尚未匹配到!"); session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response))); return; } // 3.判断当前是不是多开用户 if (onlineUserManager.getFromGameHall(user.getUserId()) != null || onlineUserManager.getFromGameRoom(user.getUserId()) != null) { 
      response.setOk(true); response.setReason("禁止多开游戏页面"); response.setMessage("repeatConnection"); session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response))); return; } // 4.设置当前玩家上线 onlineUserManager.enterGameRoom(user.getUserId(), session); // 5.把两个玩家加入到游戏房间中 synchronized (room) { 
      if (room.getUser1() == null) { 
      room.setUser1(user); // 把先连入房间的玩家作为先手方 room.setWhiteUser(user.getUserId()); System.out.println("玩家1:" + user.getUsername() + " 进入游戏房间,已经准备就绪!"); return; } if (room.getUser2() == null) { 
      // 进入到这里说明user1已经进入房间 room.setUser2(user); System.out.println("玩家2:" + user.getUsername() + " 进入游戏房间,已经准备就绪!"); // 两个玩家就绪后 // 通知玩家1 noticeGameReady(room, room.getUser1(), room.getUser2()); // 通知玩家2 noticeGameReady(room, room.getUser2(), room.getUser1()); return; } } // 6.此处如果又有玩家尝试连接同一个房间(理论上是不存在的) response.setOk(false); response.setReason("当前房间已满,您不能加入房间!"); session.sendMessage(new TextMessage(objectMapper.writeValueAsString(response))); } private void noticeGameReady(Room room, User thisUser, User thatUser) throws IOException { 
      GameReadyResponse resp = new GameReadyResponse(); resp.setOk(true); resp.setReason(""); resp.setMessage("gameReady"); resp.setReason(room.getRoomId()); resp.setThisUserId(thisUser.getUserId()); resp.setThatUserId(thatUser.getUserId()); resp.setWhiteUser(room.getWhiteUser()); // 把当前的响应数据传回给对应的玩家 WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thisUser.getUserId()); webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp))); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 
      // 1.从session里拿到当前用户信息 User user = (User) session.getAttributes().get("user"); if (user == null) { 
      System.out.println("[handleTextMessage] 当前玩家尚未登录!"); return; } // 2.根据玩家id获取到房间对象 Room room = roomManager.getRoomByUserId(user.getUserId()); // 3.通过room对象来处理这次具体的请求 room.putChess(message.getPayload()); } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { 
      User user = (User) session.getAttributes().get("user"); if (user == null) { 
      return; } WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId()); if (session == exitSession) { 
      onlineUserManager.exitGameRoom(user.getUserId()); } System.out.println("当前用户:" + user.getUsername() + " 游戏房间连接异常!"); // 通知对手获胜了 noticeThatUserWin(user); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { 
      User user = (User) session.getAttributes().get("user"); if (user == null) { 
      return; } WebSocketSession exitSession = onlineUserManager.getFromGameRoom(user.getUserId()); if (session == exitSession) { 
      onlineUserManager.exitGameRoom(user.getUserId()); } System.out.println("当前用户:" + user.getUsername() + " 离开游戏房间!"); // 通知对手获胜了 noticeThatUserWin(user); } // 判断输赢,并通知给玩家 private void noticeThatUserWin(User user) throws IOException { 
      // 1.根据当前玩家,找到玩家所在的房间 Room room = roomManager.getRoomByUserId(user.getUserId()); if (room == null) { 
      System.out.println("当前房间已经释放,无需通知对手!"); return; } // 2.根据房间找到对手 User thatUser = (user == room.getUser1()) ? room.getUser2() : room.getUser1(); // 3.找到对手的在线状态 WebSocketSession webSocketSession = onlineUserManager.getFromGameRoom(thatUser.getUserId()); if (webSocketSession == null) { 
      // 对手也掉线了 System.out.println("对手已经掉线,无需通知!"); return; } // 4.构造一个响应,通知对手,你是获胜方 GameResponse resp = new GameResponse(); resp.setMessage("putChess"); resp.setUserId(thatUser.getUserId()); resp.setWinner(thatUser.getUserId()); webSocketSession.sendMessage(new TextMessage(objectMapper.writeValueAsString(resp))); // 5.更新玩家分数信息 int winUserId = thatUser.getUserId(); int loseUserId = user.getUserId(); userMapper.userWin(winUserId); userMapper.userLose(loseUserId); // 6.释放房间对象 roomManager.remove(room.getRoomId(), room.getUser1().getUserId(), room.getUser2().getUserId()); } 

三、项目测试

1.测试用例

在这里插入图片描述

2.测试技术点

3.部分测试用例展示

(1)注册页面

 @ParameterizedTest @CsvSource({ 
     "刘云,123,1234"}) @Order(2) public void registerFail(String name, String password, String password2) throws IOException { 
      //清空登录框,以防多组登录 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#password2")).clear(); //进行注册 driver.findElement(By.cssSelector("#username")).sendKeys(name); driver.findElement(By.cssSelector("#password")).sendKeys(password); driver.findElement(By.cssSelector("#password2")).sendKeys(password2); driver.findElement(By.cssSelector("#submit")).click(); //driver转到alert Alert alert = driver.switchTo().alert(); //获取弹窗中的提示信息 String actual = alert.getText(); if (actual.equals("请先输入用户名!")) { 
      System.out.println("用户名为空!"); } else if (actual.equals("请先输入密码!")){ 
      System.out.println("密码为空!"); } else if (actual.equals("请确认密码!")) { 
      System.out.println("再次输入密码为空!"); } else if (actual.equals("两次密码输入不一致!")) { 
      System.out.println("两次密码不一致!"); } else if(actual.equals("抱歉:注册失败,请重试!")){ 
      System.out.println("已有该用户,请重试!"); } else if(actual.equals("恭喜:注册成功,是否跳转到登录页面?")) { 
      System.out.println("注册成功,跳转到登录页面!"); } else { 
      System.out.println("注册异常!"); } alert.accept(); getScreenShot(getClass().getName()); } 

(2)登录页面

 @ParameterizedTest @CsvSource({ 
     "张三,1234"}) @Order(2) public void loginFail(String name, String password) throws IOException { 
      //登录失败 try { 
      // 清空登录框,以防多组登录 driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); //登录 driver.findElement(By.cssSelector("#username")).sendKeys(name); driver.findElement(By.cssSelector("#password")).sendKeys(password); getScreenShot(getClass().getName()); driver.findElement(By.cssSelector("#submit")).click(); //获取警告框文本 String expect = "登录失败!"; Alert alert = driver.switchTo().alert(); String actual = alert.getText(); System.out.println(actual); Assertions.assertEquals(expect, actual); alert.accept(); } catch (TimeoutException e) { 
      System.out.println("登录失败:未出现警告框"); } catch (UnhandledAlertException e) { 
      System.out.println("警告框文本与预期不符:" + e.getMessage()); } } 

(3)游戏大厅页面

 @Test @Order(3) public void isMatch() throws IOException, InterruptedException { 
      // 1.先登录 driver.get("http://127.0.0.1:8081/login.html"); driver.findElement(By.cssSelector("#username")).clear(); driver.findElement(By.cssSelector("#password")).clear(); driver.findElement(By.cssSelector("#username")).sendKeys("张三"); driver.findElement(By.cssSelector("#password")).sendKeys("123"); driver.findElement(By.cssSelector("#submit")).click(); // 2.进入到游戏大厅页面后,点击匹配按钮 driver.findElement(By.cssSelector("#match-button")).click(); // 3.获取点击匹配后的信息 String actual = "匹配中...(点击停止)"; getScreenShot(getClass().getName()); String clickAfter = driver.findElement(By.cssSelector("#match-button")).getText(); // 4.判断 Assertions.assertEquals(clickAfter, actual); // 5.再次点击 driver.findElement(By.cssSelector("#match-button")).click(); String clickAgain = driver.findElement(By.cssSelector("#match-button")).getText(); // 6.判断 actual = "开始匹配"; Assertions.assertEquals(clickAgain, actual); getScreenShot(getClass().getName()); } 

(4)游戏对战页面

 // 创建驱动 private static EdgeDriver edgeDriver = createEdgeDriver(); private static ChromeDriver chromeDriver = createChromeDriver(); // 将两个不同系统的用户匹配进同一游戏房间 public void userLogin() { 
      // user1 edgeDriver.get("http://127.0.0.1:8081/login.html"); edgeDriver.findElement(By.cssSelector("#username")).sendKeys("六1"); edgeDriver.findElement(By.cssSelector("#password")).sendKeys("123"); edgeDriver.findElement(By.cssSelector("#submit")).click(); // user2 chromeDriver.get("http://127.0.0.1:8081/login.html"); chromeDriver.findElement(By.cssSelector("#username")).sendKeys("王五"); chromeDriver.findElement(By.cssSelector("#password")).sendKeys("123"); chromeDriver.findElement(By.cssSelector("#submit")).click(); // user1和user2进同一游戏房间 edgeDriver.findElement(By.cssSelector("#match-button")).click(); chromeDriver.findElement(By.cssSelector("#match-button")).click(); } / * 测试游戏对战页面 * 检查点:有棋盘、提示版元素 */ @Test @Order(1) public void testGameBoard() { 
      // 不同系统的两个用户匹配到同一个房间 userLogin(); // 测试游戏对战页面 edgeDriver.findElement(By.cssSelector("#chess")); chromeDriver.findElement(By.cssSelector("#chess")); } 

4.项目测试的结果

视频演示链接

在这里插入图片描述


完整项目代码可联系博主。

总结

这篇文章记录了五子棋项目现在已实现的功能及web页面自动化测试,后续将对该项目扩充聊天功能(同一个房间的用户可以发送消息)及测试方法。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/127844.html

(0)
上一篇 2025-09-04 19:45
下一篇 2025-09-04 20:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信