欢迎来到谢金金的博客,我们测试人员必不可少的测试离不开自动化测试,而自动化测试就会包括python+selenium+pytest的应用,以下是我基于 Pytest+Selenium 的 DeepSeek 登录功能自动化测试实践测试案例,在日常的 Web 应用测试中,登录功能作为用户访问系统的入口,其稳定性和正确性至关重要。本文将以 DeepSeek(深度求索)的登录功能为例,详细介绍如何使用 Pytest 测试框架结合 Selenium 自动化工具,实现登录场景的自动化测试,并生成直观的测试报告。

一、技术栈选型与环境准备

1. 核心技术栈说明

本次自动化测试方案选用Pytest+Selenium的组合,核心优势如下:

  • Pytest:Python 生态中最流行的测试框架之一,支持参数化测试、固件(Fixture)机制,语法简洁且扩展性强,方便批量管理测试用例。
  • Selenium:主流的 Web 自动化测试工具,支持多浏览器(Chrome、Firefox 等),能够模拟用户的真实操作(点击、输入、跳转等),适配各类 Web 应用。
  • pytest-html:Pytest 的第三方插件,用于生成美观的 HTML 测试报告,便于查看测试结果详情。

2. 环境搭建步骤

(1)安装 Python

确保本地安装 Python 3.7 及以上版本,可通过python --version命令验证版本。

(2)安装依赖包

通过 pip 命令安装所需的第三方库,执行如下命令:

bash

# 安装Pytest
pip install pytest
# 安装Selenium
pip install selenium
# 安装HTML报告插件
pip install pytest-html
(3)配置 Chrome 驱动

Selenium 操作 Chrome 浏览器需要对应版本的 ChromeDriver:

  1. 查看本地 Chrome 浏览器版本(设置→关于 Chrome);
  2. 访问ChromeDriver 官网下载匹配版本的驱动;
  3. 解压后将chromedriver.exe放入指定目录(如项目下的 “谷歌浏览器驱动” 文件夹)。

二、自动化测试框架设计

本次测试框架遵循 “模块化、可复用” 原则,分为固件层(Fixture)业务逻辑层(封装操作)测试用例层(参数化场景) 三层结构,具体设计如下:

层级 作用 核心实现
固件层 初始化 / 销毁浏览器,前置页面操作 Pytest Fixture(函数级作用域)
业务逻辑层 封装登录核心操作(输入、点击等) 自定义 login () 函数
测试用例层 设计多场景测试用例,验证登录结果 Pytest 参数化 + 断言

三、完整代码实现与解析

1. 代码结构

项目代码结构清晰,单个脚本即可完成测试(后续可扩展为多模块项目):

plaintext

deepseek_login_test/
├─ 谷歌浏览器驱动/          # 存放chromedriver.exe
└─ test_deepseek_login.py  # 核心测试脚本

2. 完整测试代码

python

运行

import pytest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.chrome.service import Service


# ---------------------- 1. 固件层:浏览器驱动初始化与前置操作 ----------------------
@pytest.fixture(scope="function")
def driver():
    """
    函数级Fixture:每个测试用例前启动浏览器,测试后关闭浏览器
    """
    # 初始化Chrome驱动(需确保chromedriver路径正确)
    service = Service("./谷歌浏览器驱动/chromedriver.exe")
    driver = webdriver.Chrome(service=service)
    driver.maximize_window()  # 最大化浏览器窗口,避免元素定位受窗口大小影响
    driver.get("https://chat.deepseek.com/sign_in")  # 打开DeepSeek登录页

    # 步骤1:等待并点击"密码登录"选项卡(默认可能是"验证码登录")
    try:
        password_login_tab = WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.XPATH,
                                        '//*[@id="root"]/div/div/div[2]/div/div/div[2]/div[1]/div[1]/div[2]/div[1]'))
        )
        password_login_tab.click()
        print("✅ 已切换到密码登录选项卡")
    except TimeoutException:
        print("❌ 超时:未找到密码登录选项卡,测试终止")
        driver.quit()
        return

    # 步骤2:验证登录表单是否加载完成(以用户名输入框为例)
    try:
        WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.CSS_SELECTOR,
                                            "#root > div > div > div._99ad066 > div > div > div.ds-sign-up-form__main > div.ds-sign-up-form__main-hero > div:nth-child(3) > div.ds-form-item__content > div > input"))
        )
        print("✅ 登录表单加载完成")
    except TimeoutException:
        print("❌ 超时:登录表单加载失败,测试终止")
        driver.quit()
        return

    yield driver  # 传递驱动给测试用例
    driver.quit()  # 测试用例执行完毕后关闭浏览器
    print("\n✅ 浏览器已关闭")


# ---------------------- 2. 业务逻辑层:封装登录操作 ----------------------
def login(driver, username, password):
    """
    登录操作封装:输入用户名、密码,点击登录按钮
    :param driver: 浏览器驱动对象
    :param username: 登录手机号
    :param password: 登录密码
    """
    # 输入用户名(手机号)
    user_input = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR,
                                    "#root > div > div > div._99ad066 > div > div > div.ds-sign-up-form__main > div.ds-sign-up-form__main-hero > div:nth-child(3) > div.ds-form-item__content > div > input"))
    )
    user_input.clear()  # 清空输入框(避免默认提示文本干扰)
    user_input.send_keys(username)
    print(f"📱 已输入用户名:{username if username else '空'}")

    # 输入密码
    pwd_input = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR,
                                    "#root > div > div > div._99ad066 > div > div > div.ds-sign-up-form__main > div.ds-sign-up-form__main-hero > div:nth-child(4) > div.ds-form-item__content > div > input"))
    )
    pwd_input.clear()
    pwd_input.send_keys(password)
    print(f"🔑 已输入密码:{'*' * len(password) if password else '空'}")

    # 点击登录按钮
    login_btn = WebDriverWait(driver, 10).until(
        EC.element_to_be_clickable((By.CSS_SELECTOR,
                                    "#root > div > div > div._99ad066 > div > div > div.ds-sign-up-form__main > div.ds-sign-up-form__main-hero > div.ds-button.ds-button--primary.ds-button--filled.ds-button--rect.ds-button--block.ds-button--l.ds-sign-up-form__register-button"))
    )
    login_btn.click()
    print("🔘 已点击登录按钮")


# ---------------------- 3. 测试用例层:参数化测试场景 ----------------------
@pytest.mark.parametrize(
    "case_name, username, password, expected",
    [
        ("场景1:正确账号密码登录", "15303054272", "3105952423", "登录成功"),
        ("场景2:错误账号登录", "13800000000", "Test123456", "账号或密码错误"),
        ("场景3:错误密码登录", "13800138000", "Wrong123", "账号或密码错误"),
        ("场景4:空账号登录", "", "Test123456", "请输入手机号"),
        ("场景5:空密码登录", "13800138000", "", "请输入密码"),
        ("场景6:无效格式账号登录", "invalid-phone", "Test123456", "请输入正确的手机号")
    ]
)
def test_deepseek_login(driver, case_name, username, password, expected):
    """
    DeepSeek登录测试用例(参数化覆盖6种核心场景)
    """
    if not driver:  # 若驱动初始化失败,直接跳过测试
        pytest.skip("驱动初始化失败,跳过测试用例")

    print(f"\n==================== 开始测试:{case_name} ====================")
    
    # 执行登录操作
    login(driver, username, password)

    # 结果验证:分"错误提示"和"登录成功"两种情况判断
    try:
        # 情况1:预期为错误提示(如空账号、格式错误等)
        error_msg = WebDriverWait(driver, 5).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, ".error"))
        ).text
        assert expected in error_msg, f"❌ 断言失败:实际提示[{error_msg}],预期包含[{expected}]"
        print(f"✅ 测试通过:{case_name}(错误提示符合预期)")
    except:
        # 情况2:预期为登录成功(通过"聊天输入框"是否出现判断)
        try:
            WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "#chat-input"))
            )
            assert "登录成功" in expected, f"❌ 断言失败:预期[{expected}],但实际登录成功"
            print(f"✅ 测试通过:{case_name}(成功进入聊天页面)")
        except TimeoutException:
            print(f"❌ 测试失败:{case_name},未检测到错误提示且未进入聊天页面")

3. 核心代码解析

(1)固件层(Fixture):driver()函数
  • 作用域scope="function"表示每个测试用例都会重新启动浏览器,避免用例间的状态干扰;
  • 显式等待:使用WebDriverWait+expected_conditions替代time.sleep(),等待元素 “可点击” 或 “存在” 后再操作,提高测试稳定性;
  • 异常处理:若前置操作(如切换登录选项卡)超时,直接关闭浏览器并终止测试,避免无效执行。
(2)业务逻辑层:login()函数
  • 封装复用:将 “输入账号 - 输入密码 - 点击登录” 的重复操作封装为函数,减少代码冗余;
  • 元素定位:结合CSS_SELECTORXPATH定位元素,优先选择稳定性高的CSS_SELECTOR(如基于类名、ID 的定位)。
(3)测试用例层:test_deepseek_login()函数
  • 参数化测试:通过@pytest.mark.parametrize一次性传入 6 种场景的测试数据,无需编写 6 个重复的用例函数;
  • 结果断言:分两种情况验证结果:
    • 错误场景:断言页面是否出现预期的错误提示(如 “请输入手机号”);
    • 成功场景:断言是否加载出登录后的 “聊天输入框”,确认登录成功。

四、测试执行与报告生成

1. 执行测试命令

在项目根目录下打开终端,执行如下命令启动测试并生成 HTML 报告:

bash

pytest test_deepseek_login.py -v --html=deepseek_login_report.html

  • -v:显示详细的测试日志(如用例名称、执行结果);
  • --html=deepseek_login_report.html:指定 HTML 报告的文件名和路径。

2. 执行过程说明

运行命令后,Chrome 浏览器会自动启动并依次执行 6 个测试场景:

  1. 每个场景前,Fixture 会初始化浏览器并切换到密码登录页;
  2. 执行登录操作后,根据预期结果进行断言;
  3. 每个场景结束后,浏览器自动关闭;
  4. 所有用例执行完毕后,在项目根目录生成deepseek_login_report.html报告文件。

3. HTML 报告解读

打开生成的 HTML 报告,可直观查看以下信息:

  • 概要:测试用例总数、通过数、失败数、跳过数、执行时长;
  • 详细结果:每个用例的名称、状态、执行时间、日志输出;
  • 错误详情:若用例失败,会显示断言失败的具体原因(如实际提示与预期不符)。
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐