测试脚本开发必备:Python核心语法与实战指南

📅 发布时间:2026/10/10 9:08:47
测试脚本开发必备:Python核心语法与实战指南
1. 为什么测试人员也得把Python语法吃透先说个真实场景你手头有一个接口要验证返回JSON里嵌套了三层还有个字段在不同环境下时有时无。用PostMan点点点能验 but 每次都得手动配环境、手动比对一百条用例点到你手麻。这时候你发现旁边同事写了个三十行的Python脚本跑一遍全完事还能自动把结果写进Excel。差别在哪不是工具的问题是语言能力的问题。Python现在几乎是测试开发的事实标准原因很简单语法门槛低、生态全、写起来快。你不需要成为语言专家但核心语法这一关必须过——变量、数据类型、流程控制、函数、文件操作、异常处理、常用内置库这些是写测试脚本的基石。本篇不是从零开始的完整教程而是围绕“测试脚本开发”这个目标把最常用的语法点串一遍配合可直接复用的代码片段。适合刚入门测试想转测试开发的同学也适合写了好几年用例但一直靠“复制粘贴改参数”过日子的朋友。2. 环境准备把Python装好并且能跑起来2.1 安装与验证不管你是Windows、macOS还是Linux装Python这件事本身不难但有几个细节值得注意。官网下载安装包时Windows下务必勾选“Add Python to PATH”不然后续在命令行里敲python会提示找不到命令很多人第一步就卡在这里。装完验证的方式很简单打开终端Windows下是cmd或PowerShell输入python --version如果输出类似Python 3.12.x说明安装成功。要是提示python不是内部或外部命令优先检查PATH。另外Windows下有时需要试py命令这是Python Launcher提供的入口很多老手也习惯用py来调用。2.2 虚拟环境每个项目一个独立空间测试脚本开发里最容易翻车的事故之一就是依赖冲突。今天装了个requests 2.31明天另一个项目需要2.24一旦全局混着装某个脚本可能就莫名其妙跑不起来了。虚拟环境就是干这个用的——每个项目隔离一套Python解释器和依赖库。# 创建虚拟环境 python -m venv venv # 激活Windows venv\Scripts\activate # 激活macOS / Linux source venv/bin/activate激活后命令行前面会出现(venv)前缀这时候再pip install的东西都装在这个环境里换项目就换环境互不干扰。我用这个方式管了五六个自动化测试项目再没遇到过依赖打架的问题。2.3 pip换源与安装常用库测试脚本开发高频使用的库无非这几类HTTP请求用requests数据处理用pandas和openpyxl断言用pytest再加一个pyyaml管配置。安装方式都是pip install 库名但国内网络环境下直接装经常慢到怀疑人生建议先把pip源换成清华或者阿里的镜像pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple也可以一次性把常用库全装上顺带把pytest这个测试框架也纳入进来后面写用例会用到pip install requests pandas openpyxl pytest pyyaml3. 核心语法拆解测试脚本最常用的那些点3.1 变量与数据类型先搞清楚你手里拿的是什么Python是动态类型语言变量不需要声明类型赋值即创建name login_test # 字符串 timeout 30 # 整数 rate 0.8 # 浮点数 is_pass True # 布尔值 payload {user: admin} # 字典写测试脚本时最怕的就是类型不匹配。接口返回的code字段是字符串200你拿整数200去比较永远不相等。所以拿到数据后先确认类型用type()函数随时检查这个习惯能省下大量排查时间。字符串、列表、字典、元组、集合这五种内置类型在测试脚本里出现频率最高。其中元组和列表看起来像但元组不可变适合存固定不变的测试数据组# 列表 - 可变可增删改 cases [case_001, case_002] cases.append(case_003) # 元组 - 不可变适合固定配置 base_url (https://api.example.com, 443) # 字典 - 键值对接口请求体和响应解析都靠它 headers {Content-Type: application/json, Authorization: Bearer xxx}3.2 字符串操作接口测试里的高频操作字符串是测试脚本里打交道最多的数据类型URL拼接、参数格式化、断言信息输出样样离不开。几个必须熟练的操作# 格式化 user admin url fhttps://api.example.com/users/{user} # f-string最推荐 url2 https://api.example.com/users/{}.format(user) # format方法 url3 https://api.example.com/users/%s % user # 老式写法不推荐 # 拼接与分割 base https://api.example.com path /login full_url base path # 简单拼接 parts a,b,c.split(,) # 按逗号分割返回 [a, b, c] # 去除空白和替换 raw admin clean raw.strip() # admin new_str raw.replace(admin, tester) # tester # 判断 assert url.startswith(https://) assert user in url个人经验所有涉及动态URL的场景一律用f-string直观且不容易出错。拼接多了括号套括号检查起来脑袋疼。3.3 流程控制让脚本具备判断和循环能力测试脚本不可能一路顺序执行到底总要判断响应码是不是200、响应时间是不是超阈值、要不要循环跑多组数据。if/else和for/while就是干这个的。条件判断要注意Python的缩进规则同一层级的代码缩进必须一致这是语法要求不是风格建议status_code 200 if status_code 200: print(请求成功) elif status_code 404: print(接口不存在) else: print(f其他状态码: {status_code})循环最常用的场景是数据驱动比如从Excel里读出一批账号密码逐个去调登录接口users [ {username: admin, password: 123456}, {username: test, password: 654321}, ] for user in users: print(f正在测试用户: {user[username]}) # 这里放HTTP请求和断言逻辑for循环配合range()可以控制执行次数配合enumerate()可以同时拿到索引和值这两组搭配在测试脚本里非常常见for i in range(5): # 重复执行5次 print(f第{i1}次尝试) for idx, user in enumerate(users): print(f索引{idx}: {user[username]})3.4 函数封装把重复逻辑提炼出来写测试脚本最大的忌讳是代码复制粘贴。你今天复制一段登录逻辑明天又要复制等到登录接口加了签名参数你有八个地方要改——这时候就知道“函数”有多重要了。Python定义函数用def关键字支持默认参数、关键字参数和可变参数def send_request(url, methodGET, payloadNone, headersNone, timeout10): 统一的HTTP请求封装 if headers is None: headers {Content-Type: application/json} # 实际请求逻辑... return response带默认参数的函数很灵活调用时可以只传必填项resp send_request(https://api.example.com/ping) resp2 send_request(https://api.example.com/login, methodPOST, payload{user: admin})函数还有一个重要概念是返回值。好的测试脚本函数职责应该单一——要么发请求、要么解析数据、要么写报告不要一个大函数从头干到尾。拆开的函数既能单独测试也能复用。3.5 文件与异常处理脚本的“防灾机制”测试脚本跑在无人值守的环境里最怕的是什么读到文件不存在、网络超时、接口返回格式和预期不符。异常处理就是给脚本装保险丝try: with open(test_data.json, r, encodingutf-8) as f: data json.load(f) except FileNotFoundError: print(测试数据文件不存在请检查路径) except json.JSONDecodeError: print(JSON格式错误无法解析) except Exception as e: print(f未知异常: {e})这里有个关键点try要圈住尽量少的代码不要一上来就把整个脚本包进去。精确捕获的异常越多定位问题时越容易。只写一个except Exception虽然省事但出了错你也只能知道“出错了”。写文件时推荐用with语句它能自动管理资源关闭省去f.close()的烦恼就算中途报错文件也不会一直占着资源。4. 实操从零搭一个接口测试脚本4.1 需求与整体设计光讲语法不落地等于白讲。这里我拿一个最常见的场景演示写一个登录接口的自动化测试脚本做数据驱动测试最后把结果写到Excel里。需求如下支持从外部JSON文件读取测试数据账号、密码、预期状态码发送POST请求到登录接口断言响应中的status字段和msg字段把每个用例的执行结果通过/失败/耗时汇总并写入Excel整体结构分为三层数据读取层、请求封装层、结果输出层。这样后续换接口、换数据源、换报告格式都只动对应模块互不影响。4.2 代码实现与逐段解读先定义数据模型结构测试数据放在JSON文件里[ {case_name: 正常登录, username: admin, password: 123456, expect_code: 200, expect_msg: success}, {case_name: 错误密码, username: admin, password: wrong, expect_code: 401, expect_msg: password error}, {case_name: 空用户名, username: , password: 123456, expect_code: 400, expect_msg: username is empty} ]然后写数据读取函数import json def load_test_data(path): 从JSON文件读取测试用例数据 with open(path, r, encodingutf-8) as f: return json.load(f)接着封装HTTP请求import requests import time def login(username, password): 调用登录接口返回响应对象 url https://api.example.com/login payload {username: username, password: password} resp requests.post(url, jsonpayload, timeout10) return resp这里有个容易踩的坑requests.post的json参数和data参数不能混用。传json时requests会自动设置Content-Type: application/json并做序列化用data就得自己处理序列化问题。大多数接口都接受JSON格式优先用json参数。最后是断言和结果组装import openpyxl from openpyxl.styles import Font def run_cases(cases): 逐条执行测试用例返回结果列表 results [] for case in cases: start time.time() try: resp login(case[username], case[password]) body resp.json() elapsed round((time.time() - start) * 1000, 2) passed (resp.status_code case[expect_code] and body.get(msg) case[expect_msg]) results.append({ case_name: case[case_name], status_code: resp.status_code, msg: body.get(msg), elapsed_ms: elapsed, passed: passed }) print(f用例[{case[case_name]}] {通过 if passed else 失败}, 耗时{elapsed}ms) except Exception as e: results.append({ case_name: case[case_name], status_code: None, msg: str(e), elapsed_ms: 0, passed: False }) return results写Excel结果def write_report(results, output_path): 将测试结果写入Excel文件 wb openpyxl.Workbook() ws wb.active ws.title 测试报告 headers [用例名称, 状态码, 响应消息, 耗时(ms), 结果] ws.append(headers) for row in results: ws.append([ row[case_name], row[status_code], row[msg], row[elapsed_ms], 通过 if row[passed] else 失败 ]) # 给表头加粗 for cell in ws[1]: cell.font Font(boldTrue) wb.save(output_path)主函数入口把整个流程串起来if __name__ __main__: cases load_test_data(login_cases.json) results run_cases(cases) write_report(results, login_report.xlsx) passed_count sum(1 for r in results if r[passed]) print(f共执行{len(results)}条用例通过{passed_count}条)实测跑下来三组用例执行加写Excel的整体耗时也就一两秒。后期要扩展加几个断言字段、换个接口、改成读数据库里的用例都是小改动。4.3 这个方案解决了什么问题在这个脚本落地之前测试人员验证登录接口是拿PostMan一个个手点的三个用例大概要五到十分钟——切换环境、复制参数、人工比对返回结果时间全花在这些操作上了。脚本化之后时间成本趋近于零而且每次执行结果都是标准化格式可直接归档。更关键的是新增用例只需往JSON里加一组数据不需要改任何代码这就是把语法基本功练扎实后带来的效率红利。5. 常见问题与排查技巧实录5.1 问题速查表很多人在写测试脚本时会反复遇到同类问题下面这张表是我在实际项目中最常帮同事排查的几类基本能覆盖80%的情况问题现象根本原因解决办法ModuleNotFoundError: No module named requests依赖未安装或装到了别的环境pip install requests确认当前激活的虚拟环境接口返回401但代码里写了200响应码判断错误或接口有鉴权打印完整响应体检查headers是否带了tokenJSON解析报错Expecting value响应不是合法JSON可能返回了HTML或空内容先resp.text看看原始内容再决定是否resp.json()字符串和数字比大小报错类型不匹配用type()确认类型必要时int()或str()转换中文字符乱码文件编码没指定打开文件时加encodingutf-8写Excel同理脚本能在本地跑打包或换机报错路径写死了本地绝对路径改成相对路径或用os.path.join()动态拼接5.2 调试技巧别迷信print但也别不用很多人调试Python脚本第一反应是到处写print。简单场景下这个办法没问题但数据量大时打印信息刷屏反而干扰定位。我的习惯是三层递进第一层关键节点打print比如请求前打印URL和参数响应后打印状态码和前200字符的内容第二层用repr()代替str()输出能看到字符串里的转义字符和边界空格而不只是打印出来的效果第三层真正复杂的问题用pdb断点调试在代码里插入breakpoint()运行到该行时进入交互模式逐步检查变量值。还有一个容易被忽视的调试利器是Python自带的logging模块。正常调试用logging.debug正式运行用logging.info输出分级管控比满屏print干净得多import logging logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logging.info(开始执行测试用例) logging.debug(f请求参数: {payload})5.3 避坑心得写测试脚本最容易忽略的3个细节第一不要用可变对象做默认参数。定义函数时写成def foo(items[])多次调用会共享同一个列表数据会“记忆”上一次调用的状态。应当写成def foo(itemsNone)函数内部再items items or []。第二读取JSON文件必须指定编码。Windows下文件默认编码可能是gbk不写encodingutf-8时只要JSON里带中文就报UnicodeDecodeError。这个坑几乎每个Windows用户都会踩一次。第三网络请求务必设置超时。requests.get(url)不设timeout的话接口卡住时脚本会一直等看起来像“死了”一样。加timeout10后10秒没响应自动报错脚本能继续往下走也方便定位慢接口。6. 从语法到工具链测试脚本开发的下一步方向6.1 用pytest管理用例生命周期上面的示例脚本已经具备自动化测试的基本形态但它还有提升空间。只用requests和assert硬写用例多了以后会有三个痛点用例筛选不变、失败后没有详细上下文、报告不够直观。pytest就是为了解决这些问题出现的。pytest的用法非常符合直觉——写普通函数函数名以test_开头就能被pytest识别为用例。上面的登录测试可以改造成pytest风格import pytest import requests def test_login_success(): resp requests.post(https://api.example.com/login, json{username: admin, password: 123456}) assert resp.status_code 200 assert resp.json().get(msg) success def test_login_wrong_password(): resp requests.post(https://api.example.com/login, json{username: admin, password: wrong}) assert resp.status_code 401 assert resp.json().get(msg) password error在终端执行pytest -v它会自动发现并运行文件里所有test_开头的函数输出每个用例的通过/失败状态。配合pytest-html插件还能生成HTML报告这在测试团队做质量汇报时非常有用。6.2 数据驱动进阶参数化pytest内置的pytest.mark.parametrize装饰器可以把多组测试数据直接挂在用例函数上减少重复代码pytest.mark.parametrize(username,password,expect_code,expect_msg, [ (admin, 123456, 200, success), (admin, wrong, 401, password error), (, 123456, 400, username is empty), ]) def test_login_parametrized(username, password, expect_code, expect_msg): resp requests.post(https://api.example.com/login, json{username: username, password: password}) assert resp.status_code expect_code assert resp.json().get(msg) expect_msg用例数据一变少代码量立刻下来。如果数据量大还可以从外部文件读取后构造参数列表实现真正的“数据与用例分离”。6.3 配置文件管理别把环境地址写死在代码里测试脚本最忌讳的就是把接口地址、账号密码、数据库连接串硬编码在代码中。环境一换开发、测试、预发布全得改。我的做法是建一个config.yaml用pyyaml读取env: test base_url: https://api-test.example.com timeout: 10 headers: Content-Type: application/jsonPython侧import yaml with open(config.yaml, r, encodingutf-8) as f: config yaml.safe_load(f) base_url config[base_url]切换环境只需要改YAML文件代码一行不动。细心的同学可能已经注意到config里如果涉及账号密码等敏感信息千万不要提交到公共仓库用环境变量或专门的密钥管理工具这也是测试开发工程化的一环。我自己在这个阶段走过不少弯路最早写的脚本全是“一坨式”的读取数据、发请求、断言、写结果全在几十行里完成。当时觉得方便后来用例一多维护成本直线上升。把脚本按职责拆成模块、用pytest管理用例、用配置文件隔离环境之后整个测试项目才真正有了“工程”的样子。Python语法本身并不难难的是把它用对地方。测试脚本的开发核心不是炫技而是用最简洁的代码解决最实际的问题。把上面这些基础点吃透配合持续的项目练习你会发现自己写脚本的速度和质量都在快速提升。遇到不会的语法查文档、看源码、写小demo验证这个过程本身就是最好的学习方式。