
1. 项目概述当智慧医疗遇上自动化测试最近在做一个智慧医疗管理平台的测试项目核心任务是把接口测试给自动化了。这活儿听起来挺常规但真做起来你会发现它和测一个普通的电商或者内容管理系统完全是两码事。智慧医疗平台它背后连着的是电子病历、在线问诊、药品库存、检查报告、医保结算甚至是一些可穿戴设备的健康数据同步。每一个接口背后可能都牵扯到复杂的业务逻辑、严格的数据合规性要求以及不容有失的稳定性。手动测光是回归测试的用例数量就能让人崩溃更别提保证每次迭代都不出岔子了。所以自动化接口测试不是“锦上添花”而是这类系统质量保障的“生命线”。我这次负责的平台就包含了患者管理、医生工作站、预约挂号、报告查询、药品配送等十几个核心模块。我们的目标很明确搭建一套稳定、高效、可维护的自动化接口测试框架能够覆盖核心业务流支持持续集成并且能快速应对需求变更。这不仅仅是写几个脚本发发请求那么简单它涉及到测试策略的制定、框架的选型、测试数据的治理、持续集成链路的打通以及如何让自动化测试真正融入研发流程成为提效和保质的利器。接下来我就把这次从零到一搭建这套体系的核心思路、踩过的坑和最终沉淀下来的实践详细拆解一遍。2. 核心需求与挑战解析在动手写第一行代码之前我们必须先把智慧医疗平台自动化接口测试的特殊性搞清楚。这决定了我们整个技术方案的设计方向。2.1 智慧医疗接口的独特性智慧医疗平台的接口和普通系统相比有几个鲜明的特点这些特点直接转化成了我们的测试需求业务链路长且复杂一个“患者完成在线问诊并获取电子处方”的流程可能涉及用户登录、医生排班查询、创建问诊订单、支付、图文/音视频问诊通信、医生开具处方、药师审核、处方推送至药房等多个接口的串联。自动化测试必须能模拟这种端到端的业务场景而不仅仅是单个接口的健壮性。数据敏感性与合规要求极高接口传输和返回的数据包含大量个人健康信息PHI如姓名、身份证号、病史、诊断结果等。测试数据的生成、使用和清理必须严格遵守数据脱敏和安全规范。我们绝不能使用真实的患者数据但又必须保证测试数据能模拟出真实的业务边界情况如罕见的疾病编码、特殊的医保类型。状态依赖性强很多接口的执行依赖于前置接口产生的状态。例如“查询检查报告”接口依赖于一个已完成的“检查申请”状态“药品发货”接口依赖于“处方审核通过”且“库存充足”的状态。测试用例需要有完善的前置状态准备和清理机制。第三方依赖多平台通常会对接医保结算接口、第三方支付网关、短信/推送服务、影像系统PACS等。自动化测试需要能灵活地模拟Mock这些外部依赖确保测试不因第三方服务不稳定而失败同时也能验证我们系统与第三方交互的逻辑是否正确。性能与稳定性要求苛刻挂号、问诊等场景可能有明显的瞬时高并发。自动化测试框架需要具备一定的压力测试能力或能与专业的性能测试工具如JMeter集成对核心接口进行基准性能测试。2.2 自动化测试的核心目标基于以上特点我们为自动化测试项目设定了几个核心目标核心业务流全覆盖确保患者从注册、问诊到购药的核心路径100%自动化覆盖。快速回归每次代码提交或每日构建后能在30分钟内完成核心接口链路的回归测试快速反馈。高可靠性测试用例本身必须稳定非产品代码问题导致的失败率误报率要低于5%。易维护性当接口变更如字段增删、路径调整时测试用例和测试数据应易于同步更新。持续集成无缝接入现有的CI/CD流水线如Jenkins、GitLab CI实现测试的自动触发和报告自动生成。团队协作测试用例、测试数据、Mock服务等资产应便于团队共享和复用。3. 技术选型与框架搭建明确了需求接下来就是技术选型。市面上接口自动化测试的工具和框架很多我们需要一套组合拳。3.1 核心测试框架选型Pytest我们没有选择传统的unittest而是选择了Pytest作为核心测试运行和编写框架。理由很充分更简洁的语法使用普通的assert语句进行断言比unittest的self.assertEqual()更符合Pythonic风格写起来更流畅。强大的Fixture机制这是Pytest的杀手级特性。我们可以用pytest.fixture来定义测试前置如登录获取token、后置操作清理测试数据、以及共享的测试数据。这对于管理智慧医疗接口那些复杂的状态依赖至关重要。例如我们可以定义一个patient_registered_fixture它依次完成患者注册、登录、并返回patient_id和token供后续问诊、预约等测试用例直接使用。丰富的插件生态pytest-html可以生成美观的HTML报告pytest-xdist支持分布式并行测试以加快执行速度pytest-base-url方便管理测试环境地址。这些插件能极大提升我们的测试工程化能力。参数化测试pytest.mark.parametrize可以轻松实现一个测试用例用多组不同数据运行非常适合测试接口的边界值和异常情况。比如测试登录接口我们可以用一组参数化数据覆盖“正确密码”、“错误密码”、“空密码”、“不存在的用户名”等多种情况。# 示例使用Pytest Fixture管理认证token import pytest import requests pytest.fixture(scopesession) def admin_token(base_url): 获取管理员tokensession级别所有测试只登录一次 login_url f{base_url}/api/auth/login payload {username: admin, password: secure_password_here} resp requests.post(login_url, jsonpayload) assert resp.status_code 200 return resp.json()[data][token] pytest.fixture def patient_context(admin_token, base_url): 创建一个测试患者并返回上下文function级别每个测试用例一个干净的患者 # 1. 调用接口创建患者 create_url f{base_url}/api/patient headers {Authorization: fBearer {admin_token}} patient_data {name: 测试患者_张三, idCard: 110101199001011234} # 注意这里是生成的测试数据 create_resp requests.post(create_url, jsonpatient_data, headersheaders) patient_id create_resp.json()[data][id] # 2. 返回包含患者ID和token的上下文字典 context {patient_id: patient_id, headers: headers} yield context # 测试用例执行时使用这里返回的context # 3. 测试用例执行完毕后清理测试患者后置操作 delete_url f{base_url}/api/patient/{patient_id} requests.delete(delete_url, headersheaders)3.2 HTTP客户端与断言Requests Pytest-Assert对于发送HTTP请求Requests库是Python社区的事实标准简单易用无需多言。对于断言除了Pytest自带的assert我们还会使用Pytest-Assert来编写更复杂的断言逻辑但它不是必须的。更关键的是我们需要对Requests进行一层简单的封装以统一处理一些通用逻辑比如自动添加基础URL和通用头信息如Content-Type。自动处理响应的JSON解析和状态码检查。集成日志记录便于调试。统一的异常处理。# 示例一个简单的HTTP客户端封装 class ApiClient: def __init__(self, base_url, default_headersNone): self.base_url base_url self.session requests.Session() if default_headers: self.session.headers.update(default_headers) # 默认添加JSON头 self.session.headers.update({Content-Type: application/json}) def request(self, method, endpoint, **kwargs): url f{self.base_url}{endpoint} # 记录请求日志实际项目中可用logging模块 print(f[Request] {method} {url}) if json in kwargs: print(f[Request Body] {kwargs[json]}) resp self.session.request(method, url, **kwargs) # 记录响应日志 print(f[Response] Status: {resp.status_code}) try: print(f[Response Body] {resp.json()}) except: print(f[Response Body] {resp.text}) # 这里可以添加通用的响应断言比如状态码非2xx/3xx时抛出异常 if not (200 resp.status_code 400): raise ApiRequestError(fRequest failed with status {resp.status_code}: {resp.text}) return resp # 便捷方法 def get(self, endpoint, **kwargs): return self.request(GET, endpoint, **kwargs) def post(self, endpoint, **kwargs): return self.request(POST, endpoint, **kwargs) # ... 其他方法3.3 测试数据管理分离与动态生成这是智慧医疗测试中最棘手也最重要的一环。我们的原则是测试数据与测试代码分离且尽可能动态生成。静态数据文件对于一些基础配置数据如固定的疾病分类代码、医院科室列表可以放在JSON或YAML文件中。# test_data/departments.yaml departments: - id: 1 name: 内科 code: NK - id: 2 name: 外科 code: WK动态数据生成对于患者、医生、订单等业务数据绝对不能用固定的真实数据。我们使用Faker库来动态生成符合业务规则的假数据。from faker import Faker import random fake Faker(zh_CN) def generate_patient_data(): 生成一个虚拟的患者数据 # 生成一个不会重复的身份证号仅用于测试 id_card fake.ssn() # 姓名 name fake.name() # 生成一个合理的手机号 phone fake.phone_number() # 性别 映射到业务编码 gender_code random.choice([1, 2]) # 1男2女 # 生成一个过去30年内的生日 birthdate fake.date_of_birth(minimum_age1, maximum_age90).strftime(%Y-%m-%d) return { name: name, idCard: id_card, phone: phone, gender: gender_code, birthdate: birthdate, allergyHistory: fake.sentence() # 过敏史描述 }重要提示对于身份证号、手机号等敏感字段Faker生成的数据虽然虚假但格式是真实的。在极端严格的环境下可以考虑使用特定前缀如TEST_或明显无效的号码如11111111111并在测试环境的后台配置中允许这些测试数据通过校验。数据清理策略采用“谁创建谁清理”的原则。利用Pytest Fixture的yield机制在测试前置创建数据测试后置清理数据确保测试环境不被污染。3.4 Mock服务应对第三方依赖WireMock对于医保、支付等第三方接口我们使用WireMock来搭建Mock服务。WireMock是一个基于HTTP的模拟服务可以录制真实请求、定义匹配规则和返回响应功能强大且独立于测试代码。优势解耦Mock服务独立部署测试框架只需关心请求和响应。灵活可以模拟各种正常、异常响应如超时、错误码。可复用一套Mock规则可以被多个测试项目共用。使用场景在测试“医保结算”流程时我们将请求指向本地的WireMock服务器它根据配置返回“结算成功”、“账户余额不足”、“医保网络异常”等不同响应从而验证我们平台的处理逻辑是否健壮。3.5 测试报告与持续集成Allure Jenkins测试报告我们选用Allure框架来生成测试报告。Allure报告非常美观能清晰展示测试用例的层级关系、执行步骤、请求响应数据、附件如截图、日志并且支持历史趋势对比。Pytest通过pytest-allure插件可以很方便地集成。持续集成使用Jenkins作为CI服务器。配置一个Pipeline任务监听代码仓库的develop分支。当有新的合并请求或推送时自动触发以下流程拉取最新代码。安装Python依赖pip install -r requirements.txt。启动WireMock等服务依赖可通过Docker Compose。运行Pytest测试套件并指定生成Allure结果文件--alluredir./allure-results。使用Allure命令行工具生成HTML报告allure generate ./allure-results -o ./allure-report --clean。将报告发布到Jenkins工作区或专门的报告服务器。根据测试结果通过率决定是否自动合并代码或通知相关人员。4. 测试用例设计与组织策略框架搭好了接下来是如何设计测试用例。好的用例结构能让维护成本大大降低。4.1 用例分层架构我们采用典型的三层架构来组织测试用例基础层Base Layer包含所有封装的工具如ApiClient、数据生成器DataFaker、通用断言函数assert_utils.py等。这一层与具体业务无关。业务层Business Layer也称为Page Object模式在API测试的变体——API Object模式。我们将每个业务模块的接口封装成独立的类。例如PatientAPI类包含创建患者、查询患者、更新患者信息的所有方法AppointmentAPI类包含预约相关的所有方法。这些方法内部调用ApiClient并返回处理后的响应数据。# api_objects/patient_api.py class PatientAPI: def __init__(self, client): self.client client def create_patient(self, patient_data): endpoint /api/v1/patients resp self.client.post(endpoint, jsonpatient_data) # 可以在这里做一些通用的响应提取或检查 return resp def get_patient_by_id(self, patient_id): endpoint f/api/v1/patients/{patient_id} return self.client.get(endpoint) # ... 其他方法测试用例层Test Case Layer这是真正的Pytest测试文件test_*.py。在这一层我们组合调用不同的API Object并添加业务断言形成完整的测试场景。一个测试函数应该只验证一个完整的业务场景。# tests/test_patient_workflow.py class TestPatientRegistrationAndQuery: def test_patient_full_lifecycle(self, api_client, generate_patient_data): 测试患者从注册到信息查询的完整流程 # 1. 初始化API对象 patient_api PatientAPI(api_client) # 2. 生成测试数据并创建患者 new_patient_data generate_patient_data() create_resp patient_api.create_patient(new_patient_data) assert create_resp.status_code 201 created_patient_id create_resp.json()[id] # 3. 查询刚创建的患者 query_resp patient_api.get_patient_by_id(created_patient_id) assert query_resp.status_code 200 queried_patient query_resp.json() # 4. 进行业务断言查询到的信息应与创建时一致 assert queried_patient[name] new_patient_data[name] assert queried_patient[idCard] new_patient_data[idCard] # ... 其他字段断言 # 5. 可选清理通常由Fixture完成这里演示断言 # 断言患者已被成功创建通过查询验证清理逻辑在Fixture的teardown中4.2 正向与异常场景设计对于每个核心接口我们至少设计两类测试用例正向流程用例验证接口在输入合法、状态正确的情况下能返回预期的成功结果。这是保障核心功能可用的基础。异常与边界用例这是提升系统健壮性的关键。我们需要覆盖参数异常必填参数缺失、参数类型错误、参数格式错误如手机号位数不对、参数值超出范围。业务状态异常执行一个操作时前置状态不满足如取消一个已完成的订单。权限异常普通用户尝试访问管理员接口或者用户A尝试操作用户B的数据。数据异常查询一个不存在的ID重复创建唯一键冲突的数据。使用Pytest的参数化可以优雅地管理这些异常用例import pytest class TestPatientCreation: pytest.mark.parametrize(invalid_data, expected_error_code, [ ({name: }, FIELD_REQUIRED), # 姓名为空 ({idCard: 123}, IDCARD_INVALID), # 身份证格式错误 ({phone: not_a_phone}, PHONE_INVALID), # 手机号格式错误 # ... 更多异常数据 ]) def test_create_patient_with_invalid_data(self, patient_api, invalid_data, expected_error_code): 参数化测试创建患者时的各种异常输入 base_data generate_patient_data() test_data {**base_data, **invalid_data} # 将异常数据合并到基础数据中 resp patient_api.create_patient(test_data) # 断言接口返回了预期的错误码和状态码如400 assert resp.status_code 400 assert resp.json()[code] expected_error_code5. 核心业务流程自动化实战理论说再多不如看一个实际例子。我们以“患者在线问诊并获取处方”这个核心业务流程为例展示如何将其自动化。5.1 场景分解与接口梳理这个长流程可以分解为以下几个原子步骤每个步骤对应一个或多个接口患者登录-POST /api/auth/login查询可预约医生-GET /api/doctors/available?deptIdxxx创建问诊订单并支付-POST /api/consultation/orders-POST /api/payment/pay进入问诊室模拟消息-POST /api/consultation/{orderId}/message(可能涉及WebSocket此处简化)医生端开具处方-POST /api/doctor/prescriptions(此操作通常需要医生角色token)患者查询处方-GET /api/patient/prescriptions?orderIdxxx5.2 测试用例实现我们需要模拟两个角色患者和医生。这里的关键是管理好两个角色的认证token和它们之间共享的业务ID如订单ID。# tests/test_consultation_prescription_workflow.py import pytest class TestConsultationToPrescriptionWorkflow: 测试从问诊到开具处方的完整流程 pytest.fixture def patient_context(self, patient_api, auth_api): 准备一个已登录的患者上下文 # 假设patient_api.create_and_login已经封装了注册和登录返回token和patient_id context patient_api.create_and_login() yield context # 后置清理注销或删除测试患者根据实际业务决定 pytest.fixture def doctor_context(self, doctor_api, auth_api): 准备一个已登录的医生上下文 context doctor_api.create_and_login() yield context def test_full_consultation_flow(self, patient_context, doctor_context): 完整的问诊-处方流程测试 # --- 阶段1患者创建问诊订单 --- patient_api patient_context[api] patient_token patient_context[token] patient_headers {Authorization: fBearer {patient_token}} # 1.1 查询可预约医生 dept_id 1 # 内科 available_doctors patient_api.get_available_doctors(dept_id, headerspatient_headers) assert len(available_doctors) 0 target_doctor available_doctors[0] # 1.2 创建问诊订单 order_data { doctorId: target_doctor[id], departmentId: dept_id, symptoms: 咳嗽、发烧三天, duration: 30 # 30分钟问诊 } create_order_resp patient_api.create_consultation_order(order_data, headerspatient_headers) assert create_order_resp.status_code 201 consultation_order create_order_resp.json() order_id consultation_order[id] # 断言订单状态为“待支付”或“已创建” assert consultation_order[status] in [CREATED, PENDING_PAYMENT] # 1.3 模拟支付成功调用支付回调接口或直接更新订单状态取决于测试环境设计 # 这里假设有一个内部接口用于测试环境模拟支付成功 payment_mock_resp patient_api.mock_payment_success(order_id, headerspatient_headers) assert payment_mock_resp.status_code 200 # 验证订单状态变为“待接诊” updated_order patient_api.get_consultation_order(order_id, headerspatient_headers).json() assert updated_order[status] WAITING_FOR_DOCTOR # --- 阶段2医生接诊并开具处方 --- doctor_api doctor_context[api] doctor_token doctor_context[token] doctor_headers {Authorization: fBearer {doctor_token}} # 2.1 医生获取待接诊订单列表并接诊该订单 waiting_orders doctor_api.get_waiting_orders(headersdoctor_headers) # 从列表中找到我们刚创建的订单可能需要根据患者名或订单ID过滤 target_order next((o for o in waiting_orders if o[id] order_id), None) assert target_order is not None accept_resp doctor_api.accept_consultation(order_id, headersdoctor_headers) assert accept_resp.status_code 200 # 验证订单状态变为“问诊中” order_in_consultation patient_api.get_consultation_order(order_id, headerspatient_headers).json() assert order_in_consultation[status] IN_CONSULTATION # 2.2 医生开具处方 prescription_data { consultationOrderId: order_id, diagnosis: 急性上呼吸道感染, medicines: [ {medicineId: MED001, name: 阿莫西林胶囊, dosage: 0.5g, frequency: 一日三次, days: 7}, {medicineId: MED045, name: 复方甘草片, dosage: 2片, frequency: 一日三次, days: 5} ], advice: 多喝水注意休息 } create_prescription_resp doctor_api.create_prescription(prescription_data, headersdoctor_headers) assert create_prescription_resp.status_code 201 prescription_id create_prescription_resp.json()[id] # 2.3 医生结束问诊 end_consult_resp doctor_api.end_consultation(order_id, headersdoctor_headers) assert end_consult_resp.status_code 200 final_order_status patient_api.get_consultation_order(order_id, headerspatient_headers).json()[status] assert final_order_status COMPLETED # --- 阶段3患者查询处方 --- # 3.1 患者查询自己的处方列表应包含刚开具的处方 patient_prescriptions patient_api.get_my_prescriptions(headerspatient_headers) assert len(patient_prescriptions) 1 # 找到对应订单的处方 new_prescription next((p for p in patient_prescriptions if p[consultationOrderId] order_id), None) assert new_prescription is not None assert new_prescription[id] prescription_id assert new_prescription[diagnosis] 急性上呼吸道感染 # 验证药品清单 assert len(new_prescription[medicines]) 2 medicine_names [m[name] for m in new_prescription[medicines]] assert 阿莫西林胶囊 in medicine_names assert 复方甘草片 in medicine_names print(f✅ 问诊处方全流程测试通过订单ID: {order_id}, 处方ID: {prescription_id})这个测试用例虽然较长但它清晰地模拟了一个完整的业务闭环。通过合理的Fixture设计patient_context,doctor_context和API对象的封装逻辑看起来并不混乱。6. 持续集成与质量门禁自动化测试脚本写好了如果不能自动运行并反馈结果其价值就大打折扣。我们将其集成到Jenkins Pipeline中。6.1 Jenkins Pipeline 配置示例我们在项目根目录创建一个Jenkinsfile定义我们的流水线。pipeline { agent any // 指定运行节点 environment { // 定义环境变量如测试环境地址、Mock服务地址 BASE_URL http://test-env.medical-platform.com MOCK_SERVER_URL http://wiremock:8080 PYTHON_PATH /usr/bin/python3 } stages { stage(Checkout) { steps { // 拉取代码 git branch: develop, url: gityour-git-repo.git } } stage(Setup Environment) { steps { script { // 安装Python依赖 sh ${PYTHON_PATH} -m pip install -r requirements.txt --upgrade pip // 如果需要启动依赖服务如WireMock假设已容器化 sh docker-compose -f docker-compose.test.yml up -d wiremock // 等待服务就绪 sh sleep 30 } } } stage(Run API Tests) { steps { script { // 运行Pytest测试生成Allure结果 sh ${PYTHON_PATH} -m pytest tests/ -v --alluredir./allure-results } } post { always { // 无论测试成功与否都生成Allure报告 allure includeProperties: false, jdk: , results: [[path: allure-results]] } } } stage(Quality Gate) { steps { script { // 读取Allure结果判断测试通过率 // 这里可以使用Allure的命令行工具或脚本解析测试结果 // 假设我们有一个简单的脚本check_pass_rate.py def passRate sh(script: ${PYTHON_PATH} scripts/check_pass_rate.py ./allure-results, returnStdout: true).trim() echo 当前测试通过率: ${passRate}% // 设置质量门禁例如通过率低于95%则判定为失败 if (passRate.toFloat() 95.0) { error(测试通过率 ${passRate}% 低于质量门禁(95%)构建失败) } } } } stage(Cleanup) { steps { script { // 停止测试依赖服务 sh docker-compose -f docker-compose.test.yml down } } } } post { always { // 构建后操作例如发送通知 emailext ( subject: 构建结果: ${currentBuild.fullDisplayName}, body: 项目 ${env.JOB_NAME} 构建 ${env.BUILD_NUMBER} 结果: ${currentBuild.currentResult}\n\n查看控制台输出: ${env.BUILD_URL}console\n\n查看Allure报告: ${env.BUILD_URL}allure, to: dev-teamyour-company.com, attachLog: true ) } success { echo 构建成功 } failure { echo 构建失败 } } }6.2 测试报告与反馈Allure报告会作为Jenkins构建产物的一部分提供链接。开发者和测试人员可以通过报告直观地看到总体通过率和趋势图。失败的测试用例详情包括错误的请求、响应、日志和截图如果附加了。每个测试用例的详细步骤便于快速定位问题发生在哪个接口调用环节。测试环境信息。当构建因测试失败而中断时相关的提交者会立即收到邮件通知可以第一时间查看报告并修复问题。7. 常见问题与避坑指南在实际落地过程中我们遇到了不少坑这里总结一下希望能帮你绕过去。7.1 测试数据污染与并发冲突问题多个测试用例并行运行时可能会创建同名的患者或使用相同的手机号导致唯一键冲突测试失败。解决方案使用随机数据确保每次生成的测试数据关键字段如手机号、身份证号是随机的。Faker库可以做到但要小心其随机种子。使用唯一标识在测试数据中加入时间戳或UUID。例如患者姓名可以设为f测试患者_{uuid.uuid4().hex[:8]}。隔离测试数据库为自动化测试准备独立的数据库或Schema并在每次测试套件运行前后进行整体清理如执行迁移脚本重置数据库。但这可能比较耗时。利用Fixture的scope合理设置Fixture的作用域。对于耗资源的操作如创建基础科室使用scopesession只执行一次。对于需要隔离的数据如患者使用scopefunction确保每个测试用例都有独立的数据。7.2 接口依赖与测试顺序问题测试用例B依赖用例A创建的数据。如果用例A失败或者用例执行顺序改变用例B也会失败。解决方案绝对避免用例间的显式依赖。每个测试用例都应该是自包含的通过自己的Fixture准备好所有前置状态。不要指望另一个测试用例为你创建数据。如果准备数据的流程非常复杂耗时比如创建一个完整的问诊订单可以将其封装成一个高层次的、scopefunction的Fixture如我们例子中的patient_with_pending_order_fixture在需要它的测试用例中直接引用。这样既保证了独立性又避免了代码重复。7.3 异步接口与超时等待问题有些操作是异步的比如“支付成功回调”、“报告生成完成”。接口调用后状态不会立即更新需要轮询查询。解决方案实现一个等待工具函数。import time from typing import Callable, Any def wait_for_condition(condition_func: Callable[[], Any], timeout30, interval2, raise_on_timeoutTrue): 等待某个条件成立 start_time time.time() while time.time() - start_time timeout: result condition_func() if result: return result time.sleep(interval) if raise_on_timeout: raise TimeoutError(fCondition not met after {timeout} seconds) return None # 使用示例等待订单状态变为“已完成” def check_order_completed(order_id): resp order_api.get_order(order_id) return resp.json()[status] COMPLETED # 在测试用例中 final_status wait_for_condition(lambda: check_order_completed(order_id), timeout60) assert final_status is not None7.4 环境配置与敏感信息问题测试环境地址、数据库密码、第三方密钥等敏感信息不能硬编码在代码中。解决方案使用环境变量或配置文件如.env文件并通过python-dotenv等库读取。在CI/CD中这些敏感信息通过Jenkins的Credentials Binding插件或类似机制注入。# config.py import os from dotenv import load_dotenv load_dotenv() # 从 .env 文件加载环境变量 BASE_URL os.getenv(TEST_BASE_URL, http://localhost:8080) DB_CONNECTION_STRING os.getenv(TEST_DB_URL) MOCK_SERVER_URL os.getenv(MOCK_SERVER_URL)在Jenkins Pipeline中stage(Run Tests) { environment { TEST_BASE_URL credentials(test-env-url) // 引用Jenkins中存储的凭据 TEST_DB_URL credentials(test-db-url) } steps { sh python -m pytest } }7.5 测试稳定性处理“脆性测试”问题测试有时成功有时失败不是因为业务逻辑问题而是因为网络波动、第三方服务不稳定、前端资源未加载完毕等环境因素。解决方案重试机制对于非幂等的查询类接口可以在测试框架层面添加重试逻辑。Pytest有pytest-rerunfailures插件。充分的等待与断言对于状态变更使用上面提到的wait_for_condition而不是简单的sleep固定时间。Mock外部依赖将支付、短信等不稳定第三方服务彻底Mock掉。隔离测试环境确保自动化测试有独立、稳定的测试环境不与手动测试或其他集成测试混用。定期清理与维护定期清理测试数据库中的垃圾数据维护测试数据脚本的更新。8. 进阶思考AI在自动化测试中的应用展望虽然我们目前的框架已经能高效运转但技术总是在发展。最近AI在测试领域的应用让我很感兴趣也做了一些探索。这里分享一些不成熟的想法算不上实践算是抛砖引玉。传统的自动化测试用例需要人工设计和维护。当业务接口频繁变更时维护成本很高。我在想能不能利用大语言模型LLM的能力来辅助甚至部分替代这部分工作比如智能生成测试用例将接口的Swagger/OpenAPI文档喂给LLM让它根据接口定义、字段描述和业务常识自动生成正向用例和一批边界值、异常值测试用例。这可以快速覆盖大量的参数组合特别是那些开发自己都容易忽略的边界情况。测试脚本自动修复当接口变更导致一批测试用例失败时LLM可以分析错误信息如返回的字段缺失或结构变化并结合最新的接口文档尝试自动修复测试脚本中的断言逻辑或请求结构。这能极大减少维护工作量。自然语言编写测试也许未来测试人员可以直接用自然语言描述测试场景“测试一个患有高血压病史的65岁男性患者成功预约心内科专家号。” 由AI助手将其翻译成可执行的测试脚本。这能降低自动化测试的编写门槛。当然这些想法离大规模、可靠的工程化应用还有距离。AI生成的用例和代码需要严格的人工审查和校准但它作为一个强大的辅助工具潜力巨大。目前我们可以先尝试用AI来辅助生成一些复杂的测试数据或者编写一些重复性的Fixture模板把人力解放出来去关注更复杂的业务场景和测试策略设计。自动化测试不是一个一劳永逸的项目而是一个需要持续投入和优化的工程。对于智慧医疗这样业务复杂、责任重大的领域一套健壮的自动化测试体系是研发团队最重要的资产之一。它不仅是质量的守护者更是团队快速、自信迭代的加速器。