Python井字棋自动化测试:Selenium超时与递归逻辑优化求助
井字棋UI测试机器人问题解决思路
核心问题分析
- 胜负元素检查超时:
WebDriverWait().until(EC.presence_of_element_located)会强制等待元素出现,游戏未结束时胜负提示元素不存在,直接触发超时异常。 - 递归死循环:原代码中递归调用
test_playTTT,每次调用都会重新初始化变量,导致游戏状态丢失且无法正常终止。
解决方案
1. 安全检查胜负元素(避免超时)
不要用强制等待元素出现的方法,改用尝试查找元素并捕获异常,或用find_elements(复数形式)判断元素是否存在(找不到时返回空列表,不会抛出异常):
def checkForWinner(self, load_browser): # 用find_elements判断元素是否存在,避免超时异常 winnerOh = load_browser.find_elements(By.XPATH, Tags.resultOh) winnerEx = load_browser.find_elements(By.XPATH, Tags.resultEx) tiedGame = load_browser.find_elements(By.XPATH, Tags.resultTie) if winnerOh: LOGGER.info('Winner O') return 'O' elif winnerEx: LOGGER.info('Winner X') return 'X' elif tiedGame: LOGGER.info('Tie') return 'None' else: # 游戏未结束,返回空字符串 return ''
如果需要等待AI落子后的短暂渲染时间,可添加带异常忽略的短时间等待:
from selenium.common.exceptions import TimeoutException def checkForWinner(self, load_browser): try: winnerOh = WebDriverWait(load_browser, 2, ignored_exceptions=[TimeoutException]).until(EC.presence_of_element_located((By.XPATH, Tags.resultOh))) LOGGER.info('Winner O') return 'O' except TimeoutException: pass try: winnerEx = WebDriverWait(load_browser, 2, ignored_exceptions=[TimeoutException]).until(EC.presence_of_element_located((By.XPATH, Tags.resultEx))) LOGGER.info('Winner X') return 'X' except TimeoutException: pass try: tiedGame = WebDriverWait(load_browser, 2, ignored_exceptions=[TimeoutException]).until(EC.presence_of_element_located((By.XPATH, Tags.resultTie))) LOGGER.info('Tie') return 'None' except TimeoutException: pass return ''
2. 替换递归为迭代循环(避免死循环)
原递归逻辑会丢失游戏状态,改用循环迭代持续进行游戏,直到分出胜负或平局:
def test_playTTT(self, load_browser): squares = [Tags.square1,Tags.square2,Tags.square3, Tags.square4,Tags.square5,Tags.square6, Tags.square7,Tags.square8,Tags.square9] clickedSquares = [] winner = '' # 循环直到游戏结束 while not winner: # 检查当前胜负状态 winner = self.checkForWinner(load_browser) if winner: break # 筛选未被点击的格子索引 available_squares = [i for i in range(9) if i not in clickedSquares] if not available_squares: # 无可用格子,判定平局 winner = 'None' break # 随机选择可用格子并点击 random_square = choice(available_squares) element = load_browser.find_element(By.XPATH, squares[random_square]) element.click() clickedSquares.append(random_square) # 等待AI落子(适配React渲染延迟) time.sleep(1) # 收集AI落子的格子(修正原逻辑错误:检查格子实际内容而非XPATH字符串) for i in range(9): square_element = load_browser.find_element(By.XPATH, squares[i]) # 假设O格子的文本为'O',可根据实际UI调整判断条件 if square_element.text == 'O' and i not in clickedSquares: clickedSquares.append(i) LOGGER.info(f"Game ended. Winner: {winner}")
3. 原代码其他问题修正
- 原代码中
if squares[i] == Tags.ohSquare逻辑错误:squares[i]是XPATH字符串,Tags.ohSquare应为O格子的实际标识(如文本、class),需改为检查元素的实际属性或内容。 - 移除不必要的递归调用,避免重复初始化变量导致的状态丢失。
内容的提问来源于stack exchange,提问作者CodenameCaptainFuture
相关产品推荐
相关产品推荐

