news 2026/10/29 11:12:27

软件测试-UI自动化-面试题2

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
软件测试-UI自动化-面试题2

请简述 Web 自动化测试执行过程中,为了提高测试效率/成功率采取了哪些措施?

主要从以下几个方面提高 Web 自动化测试的效率和成功率:

  1. 优化等待机制: 使用显式等待,等待元素加载完成后再操作,减少因页面加载不及时导致的失败。

  2. 提高脚本稳定性: 使用 POM 页面对象模型,封装公共操作,减少重复代码,方便维护。

  3. 提高执行效率: 使用数据驱动测试、并行执行等方式,减少重复操作,缩短测试时间。

  4. 增强异常处理: 对元素定位失败、超时等异常进行捕获,并添加日志和截图,方便排查问题。

  5. 优化测试用例: 优先执行核心业务和高风险用例,及时发现重要问题。

  6. 持续集成: 将自动化测试集成到 Jenkins 等 CI 工具中,实现自动执行和测试结果反馈。

记忆口诀:等待、稳定、提速、异常、用例、集成。

如何保证 Web 自动化测试的稳定性(降低脚本易用性衰减与误报率)?

主要从以下几个方面保证 Web 自动化测试的稳定性:

  1. 优化元素定位: 优先使用稳定的 ID、CSS Selector 等定位方式,避免使用容易变化的绝对 XPath。

  2. 合理设置等待: 使用显式等待,等元素加载完成、可见或可点击后再操作,减少因页面加载时序导致的失败。

  3. 做好代码封装: 使用 POM 页面对象模型,将元素定位和业务操作分离,页面变化时只需修改对应模块。

  4. 减少环境干扰: 保证测试环境、测试数据和浏览器版本相对稳定,避免外部因素影响测试结果。

  5. 完善异常处理: 对超时、元素找不到等异常进行日志记录和截图,方便定位问题。

  6. 降低误报率: 脚本失败后先分析原因,区分真实业务缺陷、脚本问题和环境问题,不要简单地将所有失败都判定为 Bug。

记忆口诀:定位稳、等待准、封装好、环境稳、日志全、误报分。

现在有一个接口自动化测试框架,如果要切换或扩展到 Web UI 自动化,应该如何设计与改造?

如果要从接口自动化扩展到 Web UI 自动化,我会采用保留公共模块、扩展 UI 专属模块的方式进行改造。

  1. 复用公共模块:保留原有的配置管理、日志、测试数据、断言、报告等模块。

  2. 引入 UI 工具:使用 Selenium 或 Playwright 实现浏览器启动、元素定位、点击、输入等操作。

  3. 采用 POM 模式:将页面元素定位和操作封装在 Page 层,测试用例只负责业务流程和结果校验,提高代码复用性。

  4. 封装公共方法:增加显式等待、异常处理、失败截图、浏览器管理等功能,提高脚本稳定性。

  5. 统一测试管理:继续使用 Pytest 管理用例,通过参数化、标记和并行执行控制测试范围,并整合测试报告。

  6. 接入持续集成:通过 Jenkins 定时或按需执行 UI 自动化,失败时保存截图和日志,方便定位问题。

总结来说,就是复用原有的公共能力,新增 UI 自动化执行层和页面对象层,统一测试执行、报告和持续集成流程。

请谈谈对 Python 异常处理机制(try-except-finally)的理解与应用。

Python 的异常处理主要通过try-except-finally实现,目的是捕获和处理程序运行过程中出现的异常,避免程序意外中断。

  1. try:放置可能发生异常的代码。

  2. except:捕获并处理异常,可以针对不同类型的异常进行处理。

  3. finally:无论是否发生异常,通常都会执行,常用于释放资源,比如关闭文件、数据库连接等。

  4. else:当try中没有发生异常时执行,可以用于处理正常执行的逻辑。

在软件测试中,我通常会使用异常处理来捕获接口请求超时、数据解析失败等异常,同时记录错误日志,方便定位问题。需要注意的是,不能直接捕获所有异常后忽略,否则可能掩盖真正的缺陷。

try: result = 10 / 0 except ZeroDivisionError as e: print(f"发生异常:{e}") else: print("程序正常执行") finally: print("执行清理操作")

这里会捕获除零异常,执行except,最后执行finally。

记忆口诀:try尝试执行,except捕获异常,else处理正常结果,finally执行清理。

Web UI 自动化测试过程中,如果有一个用例运行失败,你会如何排查和定位问题?

如果 Web UI 自动化测试用例运行失败,我会按照以下步骤进行排查:

  1. 查看日志和报告:先查看 Pytest 测试报告和错误日志,确认失败的用例、报错信息以及具体失败位置。

  2. 检查页面状态:查看失败时的页面截图,确认页面是否正常加载,是否出现弹窗、跳转异常或页面元素未显示等情况。

  3. 检查元素定位:确认元素定位方式是否正确,页面结构是否发生变化,元素是否被遮挡或不可交互。

  4. 检查等待机制:判断是否存在页面加载慢、异步请求未完成等问题,必要时使用显式等待,避免单纯依赖固定休眠时间。

  5. 检查测试数据和环境:确认测试账号、数据状态、网络连接及浏览器版本等是否正常。

  6. 复现并修复问题:手动复现失败场景,判断是业务功能缺陷、自动化脚本问题还是环境问题,针对原因修复后重新执行回归测试。

总结:我会先通过日志、报错堆栈和失败截图缩小范围,再从元素定位、等待机制、测试数据和环境等方面逐一排查,最后确认根因并验证修复结果。

三种等待方式(强制等待、隐式等待、显式等待)的区别是什么?分别在什么场景下使用?

Selenium 中常见的等待方式有三种:强制等待、隐式等待和显式等待。

1. 强制等待(time.sleep)

固定等待指定时间,不管页面是否已经加载完成,时间到了才继续执行。

  • 场景:临时调试,或者确实需要固定等待的特殊场景。

  • 缺点:容易浪费时间,等待时间不足时仍然会失败。

2. 隐式等待(implicitly_wait)

设置一个全局等待时间,在查找元素时,如果元素没有立即出现,就会在规定时间内持续尝试查找。

  • 场景:简单项目中,作为元素查找的基础等待机制。

  • 缺点:只能针对元素查找,不能直接判断元素是否可点击、是否可见等状态。

3. 显式等待(WebDriverWait)

针对特定元素或条件进行等待,满足条件后立即继续执行,超时则抛出异常。

  • 场景:等待元素出现、元素可点击、页面跳转完成等。

  • 优点:等待条件灵活,效率和稳定性通常更好,是实际 UI 自动化中优先推荐的方式。

对比项

强制等待

隐式等待

显式等待

等待方式

固定时间

查找元素时轮询

根据指定条件轮询

等待范围

当前代码位置

全局元素查找

指定操作或条件

灵活性

低

一般

高

推荐程度

尽量少用

按需使用

优先使用

import time from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 1. 强制等待 time.sleep(3) # 2. 隐式等待:全局设置 driver.implicitly_wait(10) # 3. 显式等待:等待按钮可点击 button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "submit")) ) button.click()

面试总结: 强制等待是固定等,隐式等待是查找元素时等,显式等待是满足指定条件才继续。在实际项目中,我会优先使用显式等待,减少不必要的等待时间,提高脚本的稳定性。

在 Web 自动化中如何操作下拉选择框(Select)?

在 Web 自动化中,如果下拉框是 HTML 原生的select标签,可以使用 Selenium 提供的Select类进行操作。

常见的选择方式有三种:

  1. 根据文本选择:使用select_by_visible_text()。

  2. 根据 value 属性选择:使用select_by_value()。

  3. 根据索引选择:使用select_by_index(),索引从 0 开始。

如果是自定义下拉框,例如使用 Vue 或 React 实现的下拉组件,通常不能直接使用Select类,需要先点击下拉框,再定位并点击对应的选项。

from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import Select element = driver.find_element(By.ID, "city") select = Select(element) # 根据文本选择 select.select_by_visible_text("北京") # 根据 value 属性选择 select.select_by_value("shanghai") # 根据索引选择,索引从 0 开始 select.select_by_index(2)

面试总结: 原生下拉框使用Select类,通过文本、value 或索引选择;自定义下拉框则通过普通元素定位和点击来操作。操作前需要确认下拉框类型,避免使用错误的方法。

如何处理页面中的弹出框(Alert/Confirm/Prompt 及自定义弹窗)?

在 Web UI 自动化中,我会根据弹出框的类型选择不同的处理方式,主要分为浏览器原生弹窗和页面自定义弹窗。

1. Alert 提示框

使用switch_to.alert切换到弹窗,然后调用accept()确认关闭。

2. Confirm 确认框

调用accept()确认,调用dismiss()取消。

3. Prompt 输入框

使用send_keys()输入内容,再调用accept()确认,也可以使用dismiss()取消。

4. 自定义弹窗

自定义弹窗属于网页 DOM 的一部分,通常使用 Selenium 的元素定位方式找到弹窗中的按钮或输入框,再进行点击、输入等操作。必要时使用显式等待,确保弹窗已经出现。

from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 1. Alert 弹窗 alert = driver.switch_to.alert print(alert.text) alert.accept() # 2. Confirm 确认框:取消操作 driver.switch_to.alert.dismiss() # 3. Prompt 输入框 alert = driver.switch_to.alert alert.send_keys("测试内容") alert.accept() # 4. 自定义弹窗:等待并点击关闭按钮 close_btn = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.CSS_SELECTOR, ".modal-close")) ) close_btn.click()

注意:示例中的弹窗需要在对应操作前已经出现,实际项目中应先通过显式等待确认弹窗出现;自定义弹窗的 CSS 选择器也需要根据实际页面修改。

面试总结: 浏览器原生弹窗使用switch_to.alert,通过accept()、dismiss()和send_keys()操作;自定义弹窗则通过 DOM 元素定位和显式等待进行处理。

如何通过自动化脚本控制页面的滚动条?

在 Web UI 自动化中,我主要使用 Selenium 结合 JavaScript 或键盘操作来控制页面滚动,常见有以下三种方式:

  1. JavaScript 滚动:通过execute_script()控制页面滚动到指定位置,适合滚动到顶部、底部或指定坐标。

  2. 滚动到指定元素:使用 JavaScript 的scrollIntoView(),让目标元素滚动到可见区域,方便后续操作。

  3. 键盘滚动:使用 Selenium 的send_keys()模拟按上下方向键、Page Down 等按键,适合模拟用户操作。

from selenium.webdriver.common.by import By # 1. 滚动到页面底部 driver.execute_script( "window.scrollTo(0, document.body.scrollHeight)" ) # 2. 滚动到页面顶部 driver.execute_script("window.scrollTo(0, 0)") # 3. 滚动到指定元素 element = driver.find_element(By.ID, "submit") driver.execute_script( "arguments[0].scrollIntoView({block: 'center'})", element )

面试总结: 我通常优先使用 JavaScript 控制滚动,尤其是scrollIntoView(),可以将目标元素滚动到可见区域,方便后续定位和操作。如果需要模拟真实用户的滚动行为,也可以使用键盘或鼠标滚轮操作。

如何处理网页中的嵌套框架(iframe/frame)?

在 Web UI 自动化中,iframe或frame中的元素不能直接从主页面定位,需要先切换到对应的框架,再进行元素操作。

Selenium 中常用三种切换方式:

  1. 根据索引切换:switch_to.frame(0)。

  2. 根据元素切换:先定位 iframe 元素,再传入switch_to.frame()。

  3. 根据 name 或 id 切换:switch_to.frame("frame_name")。

如果是嵌套 iframe,需要逐层切换进去;操作完成后,可以使用parent_frame()返回上一层,或者使用default_content()返回最外层页面。

from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待并切换到 iframe WebDriverWait(driver, 10).until( EC.frame_to_be_available_and_switch_to_it( (By.ID, "my_frame") ) ) # 操作 iframe 内的元素 driver.find_element(By.ID, "username").send_keys("test") # 返回主页面 driver.switch_to.default_content()

面试总结: 处理 iframe 的关键是先切换框架,再定位元素。嵌套框架需要逐层切换,操作完成后及时返回主页面,避免因框架上下文不正确导致元素定位失败。

如何处理浏览器多选项卡/标签页(Tabs)之间的切换与跳转?

在 Web UI 自动化中,Selenium 通过window_handles获取所有窗口句柄,通过switch_to.window()切换到指定窗口或标签页。

常见操作有三种:

  1. 获取窗口句柄:使用driver.window_handles获取所有窗口的句柄。

  2. 切换窗口:使用driver.switch_to.window(handle)切换到指定窗口。

  3. 关闭窗口:使用driver.close()关闭当前窗口;使用driver.quit()关闭整个浏览器会话。

实际项目中,如果点击链接后打开新标签页,我会先获取原窗口句柄,再等待新窗口出现,最后切换过去进行操作。不要直接假设新窗口一定是列表中的第二个。

from selenium.webdriver.support.ui import WebDriverWait # 保存原窗口句柄 original_window = driver.current_window_handle # 点击链接,打开新标签页 driver.find_element("id", "open_tab").click() # 等待新窗口出现 WebDriverWait(driver, 10).until( lambda d: len(d.window_handles) > 1 ) # 找到并切换到新标签页 for handle in driver.window_handles: if handle != original_window: driver.switch_to.window(handle) break # 在新标签页中操作 print(driver.title) # 关闭当前标签页,返回原标签页 driver.close() driver.switch_to.window(original_window)

面试总结: 先保存原窗口句柄,再等待新窗口出现,通过句柄切换标签页;操作完成后,根据需要关闭当前窗口并切回原窗口。关键是正确管理窗口句柄,避免切换错误或操作已关闭的窗口。

你们项目中 UI 自动化和接口自动化的覆盖率分别是多少?

我们项目中,接口自动化的覆盖率相对较高,主要覆盖核心业务接口和高频回归场景;UI 自动化的覆盖率相对低一些,主要覆盖核心业务流程和关键功能。

接口自动化主要使用 Python、Requests 和 Pytest,重点验证接口的请求参数、响应结果、业务逻辑和异常场景。

UI 自动化主要使用 Selenium,重点覆盖登录、核心页面操作和关键业务流程。

整体上,我们采用接口自动化为主、UI 自动化为辅的策略,因为接口自动化执行速度快、维护成本相对较低,而 UI 自动化更适合验证用户实际操作流程。

需要注意的是,具体覆盖率应该以项目实际统计数据为准。如果面试官追问百分比,说明统计口径,例如核心接口覆盖率、核心业务流程覆盖率,而不是随意给出一个数字。

自动化测试脚本是如何进行调试(Debug)的?

在 Web UI 自动化测试中,我主要通过以下几种方式调试脚本:

  1. 查看报错信息:通过 Pytest 的报错信息和异常堆栈,定位具体失败的代码行,判断是元素定位、等待超时还是其他问题。

  2. 增加日志输出:使用logging记录关键操作、页面状态和执行结果,方便追踪脚本的执行过程。

  3. 使用断点调试:通过 PyCharm 或 VS Code 设置断点,逐步执行代码,检查变量值和程序运行状态。

  4. 检查页面元素:使用浏览器开发者工具检查 HTML 结构和元素属性,确认定位表达式是否正确。

  5. 截图和复现:在失败时保存页面截图,必要时结合浏览器控制台日志进行排查,并单独运行失败用例复现问题。

  6. 修复并回归验证:找到原因后修改脚本,再重新执行相关用例,确认问题已解决且没有引入新的问题。

import logging from selenium.webdriver.common.by import By logging.basicConfig(level=logging.INFO) logging.info("开始执行登录测试") try: button = driver.find_element(By.ID, "login") logging.info("已找到登录按钮") button.click() except Exception: logging.exception("登录操作失败") driver.save_screenshot("error.png") raise

面试总结: 我通常先看报错堆栈,再结合日志、断点、浏览器开发者工具和失败截图定位问题,修复后重新执行用例验证。调试的关键是先找到根因,而不是简单地增加等待时间或反复重跑脚本。

pytest 框架中常用的插件和装饰器有哪些?

一、常用插件

  1. pytest-html:生成 HTML 格式的测试报告,方便查看用例执行结果。

  2. pytest-xdist:支持多进程并行执行测试用例,提高执行效率。

  3. pytest-rerunfailures:支持失败用例自动重跑,辅助排查偶发性失败,但不能代替根因分析。

  4. allure-pytest:生成 Allure 测试报告,展示用例步骤、执行结果和失败信息。

  5. pytest-cov:统计 Python 代码覆盖率,主要用于代码覆盖率分析,不等同于测试用例覆盖率。

二、常用装饰器和标记

  1. @pytest.mark.parametrize:参数化测试,一组测试逻辑可以使用多组数据执行。

  2. @pytest.mark.skip:无条件跳过某个测试用例。

  3. @pytest.mark.skipif:满足指定条件时跳过用例。

  4. @pytest.mark.xfail:标记预期会失败的用例。

  5. @pytest.mark.smoke:自定义标记,用于标识冒烟测试用例,需要提前注册标记。

  6. @pytest.fixture:定义测试前置、后置操作或测试资源,例如初始化浏览器、准备测试数据和清理环境。

import pytest @pytest.mark.parametrize("username, password", [ ("admin", "123456"), ("test", "654321") ]) def test_login(username, password): assert username != "" assert password != "" @pytest.fixture def setup_data(): print("准备测试数据") yield print("清理测试数据") @pytest.mark.skipif( True, reason="暂时跳过" ) def test_demo(): assert True

插件主要用于扩展 Pytest 的能力,例如报告生成、并行执行和失败重跑;装饰器和标记主要用于参数化、用例跳过、预期失败及前后置管理。其中我会重点掌握parametrize、fixture、skip、skipif和xdist。

你在自动化测试中是如何做断言(Assert)的?

在自动化测试中,我主要使用 Pytest 自带的assert语句进行断言,判断实际结果是否符合预期结果。

常见的断言方式有以下几种:

  1. 状态断言:判断接口状态码是否为 200,或者页面元素是否显示。

  2. 数据断言:判断接口返回的字段值、数据类型是否符合预期。

  3. 业务断言:判断业务操作是否成功,例如登录后是否跳转到首页。

  4. 数据库断言:对于涉及数据库的场景,可以查询数据库,验证数据是否正确保存或更新。

实际项目中,我会根据测试场景选择合适的断言,同时在断言失败时结合日志和报错信息定位问题。

# 接口断言 assert response.status_code == 200 assert response.json()["code"] == 0 assert response.json()["data"]["name"] == "test" # Web UI 断言 assert driver.title == "首页" assert driver.find_element( "id", "welcome" ).is_displayed()

面试总结: 我主要使用 Pytest 的assert,从状态、数据、业务流程和数据库等维度验证结果。断言不仅要判断请求是否成功,还要验证实际业务结果是否符合预期,避免出现状态码正常但业务逻辑错误的情况。

Python 中的 re 正则表达式模块常用方法有哪些?它们之间有什么区别?

Python 的re模块主要用于字符串匹配、查找、替换和分割,在接口自动化测试中,可以用来提取响应数据、匹配验证码格式或校验字符串。

常用方法主要有以下六种:

  1. re.match():从字符串开头开始匹配,开头不符合就匹配失败。

  2. re.search():扫描整个字符串,找到第一个符合条件的位置就返回。

  3. re.findall():查找所有符合条件的内容,以列表形式返回。

  4. re.finditer():查找所有匹配结果,返回迭代器,适合逐个处理匹配对象。

  5. re.sub():替换符合正则表达式的内容。

  6. re.split():根据正则表达式匹配到的位置分割字符串。

import re text = "订单号:123,订单号:456" print(re.match(r"\d+", text)) # None print(re.search(r"\d+", text).group()) # 123 print(re.findall(r"\d+", text)) # ['123', '456'] print(re.sub(r"\d+", "*", text)) # 订单号:*,订单号:* print(re.split(r"\d+", text)) # ['订单号:', ',订单号:', '']

方法

主要作用

返回结果

match()

从开头匹配

匹配对象或None

search()

查找第一个匹配

匹配对象或None

findall()

查找全部匹配

列表

finditer()

逐个遍历匹配结果

迭代器

sub()

替换匹配内容

字符串

split()

按匹配位置分割

列表

面试总结:match从头匹配,search查找第一个,findall查找全部,sub用于替换,split用于分割,finditer则适合逐个遍历匹配结果。

pytest 框架是如何实现数据驱动测试(DDT)的?

Pytest 主要通过@pytest.mark.parametrize装饰器实现数据驱动测试(DDT)。

它可以将测试数据和测试逻辑分离,同一个测试函数使用多组不同的数据执行,减少重复代码,提高测试效率。

实际项目中,我通常会把测试数据放在列表、字典、YAML 或 JSON 文件中,再通过参数化机制传入测试用例。例如,接口自动化测试中,可以使用不同的用户名、密码和预期结果,验证登录接口的正常和异常场景。

import pytest @pytest.mark.parametrize("username, password, expected", [ ("admin", "123456", 200), ("test", "wrong", 401), ("", "123456", 400) ]) def test_login(username, password, expected): response = send_login_request(username, password) assert response.status_code == expected

这里的send_login_request()是示意函数,需要在实际项目中实现。

面试总结: Pytest 主要通过@pytest.mark.parametrize实现数据驱动测试,也可以结合 YAML、JSON 等外部数据文件管理测试数据。核心思想是一套测试逻辑,多组测试数据,分别执行并验证结果。

如果一个接口的响应出参有十几万条数据,应该如何进行校验和测试?

如果一个接口的响应数据有十几万条,我不会直接逐条人工检查,而是根据数据特点采用自动化校验,主要从以下几个方面入手:

  1. 校验整体结构:检查 HTTP 状态码、响应格式、字段类型和必填字段是否符合预期。

  2. 校验数据完整性:检查数据总量、是否存在重复数据、关键字段是否为空,以及是否存在缺失数据。

  3. 校验数据正确性:通过抽样、边界值检查,或者与数据库、基准数据进行比对,验证数据内容是否正确。

  4. 分批或分页校验:如果接口支持分页,可以逐页获取数据并进行校验,避免一次性加载大量数据导致内存占用过高。

  5. 检查性能表现:记录接口响应时间、数据传输量和内存使用情况,判断是否满足性能要求。

对于大量数据,我会使用 Python 编写自动化校验脚本,通过集合、计数、哈希值等方式提高校验效率。如果需要完整验证,就进行全量比对;如果成本较高,则结合风险进行抽样,但不会用抽样代替必须的完整性校验。

data = response.json()["data"] ids = set() for item in data: assert item.get("id") is not None assert item.get("name") is not None assert item["id"] not in ids, "发现重复 ID" ids.add(item["id"]) print(f"校验通过,共 {len(data)} 条数据")

这段代码适用于响应数据已经加载到内存的情况。如果数据量更大,可以考虑流式解析或分页处理。

总结: 大数据量接口测试的重点是数据结构、完整性、正确性和性能。根据业务要求选择全量校验、分页校验或抽样校验,并尽量使用自动化脚本代替人工检查。

你觉得如何设计一个优秀的自动化测试框架?需要考虑哪些核心要素?

我认为,一个优秀的自动化测试框架,核心是易维护、可复用、执行稳定、方便扩展。设计时我主要考虑以下六个方面:

  1. 分层设计:将框架划分为配置层、数据层、公共方法层、业务封装层、测试用例层和报告层,降低模块之间的耦合。

  2. 数据驱动:使用 YAML、JSON 等文件管理测试数据,结合 Pytest 参数化,实现测试数据与测试逻辑分离。

  3. 公共方法封装:封装请求发送、元素定位、等待、断言、日志记录等公共功能,减少重复代码。

  4. 稳定性保障:合理使用显式等待、异常处理、测试数据隔离和资源清理,减少脚本失败和误报。

  5. 测试报告与日志:集成 Allure 等报告工具,记录执行结果、异常堆栈和失败截图,方便定位问题。

  6. 持续集成与扩展性:接入 Jenkins,实现自动执行、失败通知和回归测试,并支持并行执行,以及后续扩展接口、Web UI 等自动化测试类型。

此外,还需要考虑代码规范、版本管理、执行效率和框架的维护成本,避免为了追求复杂架构而过度设计。

总结: 我设计自动化测试框架时,会优先考虑分层解耦、公共能力复用、数据驱动、执行稳定、结果可追溯和持续集成,让框架不仅能够运行测试,还能长期维护并适应业务变化。

你在实际项目测试过程中,哪些地方或业务模块经常会出现 Bug?

在实际项目中,我认为 Bug 比较容易集中在以下几个方面:

  1. 复杂业务逻辑:例如角色创建、消息发送、内容生成等,涉及多个业务规则和状态流转,容易出现逻辑错误。

  2. 接口交互和数据一致性:多个接口之间存在依赖关系时,容易出现参数传递错误、数据不同步、重复提交等问题。

  3. 边界值和异常场景:例如输入为空、超长字符、网络超时、重复点击等,开发容易遗漏处理。

  4. 多端兼容问题:不同手机型号、操作系统和屏幕尺寸,可能导致页面显示异常或功能表现不一致。

  5. 并发和性能问题:例如多人同时操作、消息高频发送时,可能出现响应缓慢、数据重复或服务异常。

  6. 新功能影响旧功能:版本迭代后,修改某个模块可能影响其他模块,因此需要重点进行回归测试。

以我测试过的 AI 社交类 App 为例,消息发送、角色创建和 AI 内容生成这类涉及多模块交互的功能,我会重点关注正常流程、异常处理、数据一致性以及弱网场景。

面试总结: 我会重点关注业务逻辑复杂、接口依赖多、边界场景多以及跨模块交互频繁的地方,因为这些场景更容易暴露问题。同时结合历史缺陷分布和需求变更情况,动态调整测试重点。

针对业务需求“会员卡送附属卡,消费享受两倍积分,每 100 积分兑换指定奖励”,你会如何设计测试用例?

针对这个需求,我会从功能测试、边界值测试、异常测试、数据一致性测试和业务流程测试几个方面设计用例。

首先,我会确认几个业务规则:一张会员卡可以赠送几张附属卡、主卡和附属卡是否都享受双倍积分、消费金额与积分如何换算、积分不足 100 时是否可以兑换,以及兑换后积分如何扣减。

假设主卡和附属卡都享受双倍积分,每消费 1 元获得 1 积分,每满 100 积分可以兑换指定奖励,我会设计以下测试用例。

一、会员卡及附属卡功能

  1. 购买或办理会员卡,验证是否成功赠送附属卡。

  2. 验证主卡与附属卡的绑定关系是否正确。

  3. 验证附属卡是否可以正常使用。

  4. 验证重复领取、重复绑定或超出附属卡数量限制时,系统是否正确处理。

二、双倍积分功能

  1. 主卡消费 100 元,验证是否获得 200 积分。

  2. 附属卡消费 100 元,验证是否获得 200 积分。

  3. 消费 0 元,验证是否不产生积分。

  4. 消费金额为小数,例如 10.5 元,验证积分计算和取整规则是否正确。

  5. 退款后,验证积分是否按照业务规则扣回。

  6. 重复提交消费请求,验证是否会重复累计积分。

三、积分兑换功能

  1. 积分达到 100 分时,验证是否可以兑换指定奖励。

  2. 积分不足 100 分时,验证是否禁止兑换。

  3. 积分为 250 分时,验证是否可以兑换两次,剩余 50 分。

  4. 兑换成功后,验证积分是否正确扣减,奖励是否正确发放。

  5. 奖励库存不足、奖励已下架时,验证兑换是否失败并给出提示。

  6. 连续点击兑换或并发兑换时,验证是否出现重复扣分或重复发奖。

四、数据及异常测试

  1. 验证主卡和附属卡的消费积分是否按照业务规则累计到正确的账户。

  2. 验证积分流水、消费记录和账户余额是否一致。

  3. 模拟网络超时、重复请求等情况,验证积分和奖励数据是否正确。

  4. 验证积分临界值,例如 99、100、101 分时的兑换结果。

  5. 验证兑换过程中出现异常时,是否能够保证积分扣减与奖励发放的数据一致性。

面试总结: 我会重点关注双倍积分计算、100 积分兑换门槛、主附属卡的积分归属,以及重复请求和并发兑换等场景。同时结合等价类、边界值分析和异常场景设计测试用例,确保积分计算准确、奖励发放正确、数据一致。

Python 中的反射函数(getattr, setattr, hasattr 等)怎么用?应用场景是什么?

Python 的反射是指在程序运行过程中,动态获取、判断、调用或修改对象的属性和方法。

常用的反射函数主要有四个:

  1. getattr():获取对象的属性或方法,也可以设置默认值。

  2. setattr():动态设置或修改对象的属性。

  3. hasattr():判断对象是否存在指定属性。

  4. delattr():删除对象的指定属性。

class Login: def __init__(self): self.username = "admin" def login(self): return "登录成功" obj = Login() # 获取属性 print(getattr(obj, "username")) # admin # 判断属性是否存在 print(hasattr(obj, "login")) # True # 动态调用方法 method = getattr(obj, "login") print(method()) # 登录成功 # 动态设置属性 setattr(obj, "password", "123456") print(obj.password) # 123456 # 删除属性 delattr(obj, "password")

在自动化测试中的应用场景

  1. 关键字驱动测试:根据测试数据中的关键字,动态调用对应的测试方法,例如点击、输入、登录等操作。

  2. 动态调用接口:根据配置文件中的方法名称,选择对应的请求处理方法。

  3. 框架扩展:动态检查对象是否具有某个方法,方便进行插件管理或公共方法调用。

例如,在关键字驱动框架中,可以使用getattr()根据配置动态调用对应的方法,避免编写大量的if-else判断。

面试总结: 反射的核心是动态操作对象的属性和方法。在自动化测试框架中,常用于关键字驱动、动态方法调用和框架扩展。使用时要注意校验方法名称,避免调用不存在或不允许执行的方法。

Unittest 和 pytest 测试框架的区别是什么?

Unittest 和 pytest 都是 Python 的测试框架,主要区别在于用例编写方式、断言方式、前置后置处理和扩展能力。

  1. 用例编写: Unittest 通常需要继承TestCase类,pytest 不需要继承,直接编写以test_开头的函数即可。

  2. 断言方式: Unittest 使用assertEqual()、assertTrue()等断言方法;pytest 直接使用 Python 的assert语句。

  3. 前置后置: Unittest 使用setUp()和tearDown();pytest 使用fixture,更加灵活。

  4. 参数化: Unittest 可以通过循环等方式实现参数化;pytest 使用@pytest.mark.parametrize,更加方便。

  5. 扩展能力: pytest 插件丰富,支持测试报告、并行执行、失败重跑等功能,扩展性比较强。

总结: Unittest 是 Python 标准库自带的测试框架;pytest 使用更加简洁,功能和插件生态更丰富,因此在自动化测试项目中比较常用。

简单代码对比

Unittest: import unittest class TestLogin(unittest.TestCase): def test_login(self): self.assertEqual(1 + 1, 2) pytest: def test_login(): assert 1 + 1 == 2

面试加分点: 我实际开展自动化测试时,更倾向于使用 pytest,因为它编写用例比较简洁,并且可以结合fixture、参数化和 Allure 报告等功能,提高自动化测试效率。

App 端和 Web 端的上线发布流程有什么区别?

App 端和 Web 端上线发布的主要区别在于:Web 端通常部署服务器后即可更新,而 App 端通常还需要经过应用商店审核和用户下载安装或更新。

1. Web 端发布流程:

  • 开发完成后,测试人员进行功能、兼容性、接口和回归测试。

  • 测试通过后,提交预发布环境验收。

  • 验收通过后,开发或运维将代码部署到生产服务器。

  • 发布后进行线上验证,检查核心功能和接口是否正常。

  • 如果出现严重问题,可以回滚代码或恢复之前的版本。

2. App 端发布流程:

  • 开发完成后,测试人员进行功能、兼容性、安装卸载、升级、弱网、性能等测试。

  • 测试通过后,进行预发布验收,并打包生成 Android APK/AAB 或 iOS 安装包。

  • 提交应用商店审核,审核通过后发布;企业内部应用也可能通过内部渠道分发。

  • 发布后关注崩溃率、接口异常和用户反馈,必要时通过热修复、回滚服务端或发布新版本处理问题。

核心区别

对比项

Web 端

App 端

发布方式

部署服务器

打包后通过商店或其他渠道分发

更新方式

用户刷新页面通常即可获取新版本

通常需要下载或安装更新

重点测试

浏览器兼容性、页面和接口

设备兼容性、安装升级、系统权限、弱网、性能

发布限制

主要受部署流程和服务器环境影响

还可能受到应用商店审核、系统版本和渠道限制

回滚方式

通常可回滚代码或部署版本

服务端可以回滚,但客户端已安装版本不一定能立即回退

总结: Web 端上线更侧重服务器部署和线上验证;App 端除了功能测试,还要重点关注安装包、设备兼容性、应用商店审核和版本升级。两者上线后都需要进行线上监控和问题跟踪。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 11:11:39

obs录屏

【干货】把 OBS 拆到骨头:手把手带你用 libobs 撸一个 40MB 的轻量录屏工具 收藏吃灰警告 ⚠️:本文不是「怎么用 OBS」,而是「怎么把 OBS 当库用」的保姆级拆解,含 5 个让你少走弯路的踩坑经验。建议先点赞收藏,慢慢看…

作者头像 李华
网站建设 2026/10/29 11:11:37

物理AI的核心挑战在于获取符合物理规律的训练数据

2026年10月24日至25日,CSDN在长沙世界计算长沙智谷举办了"2026长沙1024程序员日暨AI构建者大会",主题为"具身同行,智构未来",线下参会人数超1500人。 大会以具身智能与物理AI为主线,设置了开幕式暨…

作者头像 李华
网站建设 2026/10/29 11:10:47

VCP-CLIP

文章目录AbstractIntroductionRelated WorkPrompt learningZero-shot anomaly segmentationMethodProblem DefinitionThe design of baseline、The design of VCP-CLIPPre-VCPPost-VCPTraining and InferenceLoss FunctionInferenceExperimentExperimental SetupComparison wit…

作者头像 李华
网站建设 2026/10/29 11:10:33

和弦图分析

和弦图分析:学生成绩数据一、什么是和弦图和弦图是一种用“环状节点 连接弦线”来展示多个对象之间关系的图表。通常所有对象均匀分布在一个圆周上,任意两个对象之间若有联系,就用一条从一方弧向另一方的弦连接起来。和弦图常用来呈现相关性…

作者头像 李华