为什么要在 Linux 环境里做测试
绝大多数服务端程序最终都跑在 Linux 上:线上服务器、容器、CI 流水线,底层几乎都是发行版。如果你的开发机是 Windows 或 macOS,本地”跑得过”并不代表线上没问题——文件路径大小写敏感、行尾符差异、依赖库版本、systemd 服务行为,这些坑只有在真正的 Linux 环境里才会暴露。所以”在 Linux 环境下测试”不是可有可无的加分项,而是让”我本地是好的”这句话真正站得住的必经一步。
本文按”环境怎么搭 → 测试怎么分层跑 → 结果怎么看 → 怎么自动化”的顺序,给出一套可以直接照做的流程。
第一步:选一个可复现的测试环境
测试环境的第一原则是可复现、可丢弃。三种常见方案:
- Docker 容器:最推荐。一条命令拉起与生产同版本的发行版,测完即删,互不污染。
- 虚拟机:适合需要内核级行为( systemd、网络栈、挂载 )的测试,推荐配合快照使用。
- WSL2:Windows 用户的轻量选择,跑用户态测试足够,但涉及内核模块、硬件驱动的场景不适用。
以 Docker 为例,进入一个与生产一致的 Ubuntu 环境:
docker run -it --rm -v "$PWD":/work -w /work ubuntu:22.04 bash
apt-get update && apt-get install -y python3-pip build-essential
python3 -m pip install pytest
关键是把自己项目的代码目录挂载进去(-v "$PWD":/work),并在 Dockerfile 或脚本里固化依赖安装命令,保证任何人、任何机器都能重建同一个环境。
第二步:按层次跑测试,从快到慢
不要把”跑测试”理解成一条命令等到底。合理的顺序是先跑快的、再跑慢的,让明显的错误在十秒内暴露:
- 单元测试:只测函数和类,不碰网络和磁盘。Python 项目用
python3 -m pytest tests/unit -q,C/C++ 项目常见make test或 CTest。 - 集成测试:把数据库、消息队列等依赖用 docker compose 拉起来,验证模块拼装后的行为。
- 接口/功能测试:对服务本体发请求,curl 加断言脚本即可起步。
- 性能与稳定性测试:最后跑,也最容易被跳过,下面单独讲。
# 集成测试:先起依赖,再跑用例
docker compose -f tests/docker-compose.test.yml up -d db redis
python3 -m pytest tests/integration -q
docker compose -f tests/docker-compose.test.yml down -v
第三步:性能与压力测试的常用工具
Linux 下做性能测试的工具链非常成熟,按对象选工具:
- HTTP 接口:
ab(Apache Bench)最上手,wrk/hey适合压高并发。ab -n 1000 -c 50 http://127.0.0.1:8080/api/health表示 50 并发打 1000 次请求。 - 数据库:sysbench 的 oltp 套件可以模拟读写混合负载,直接对比索引调整前后的 QPS。
- 系统瓶颈定位:压测同时开着
top、iostat -x 1、vmstat 1,看 CPU 是卡在用户态还是 iowait,内存是否触发 swap。
压测的黄金法则:只改一个变量。同一环境、同一数据集、同一并发数,改配置前后各跑三轮取中位数,否则结果没有对比价值。
第四步:把结果变成可追溯的记录
测试跑完只看到满屏绿字是不够的,要留下能复盘的产物:
- 让测试框架输出机器可读的报告:pytest 加
--junitxml=report.xml,go 测试加-v重定向。 - 性能测试把每轮数据存成 CSV 或 JSON,附上环境信息(内核版本、CPU 型号、数据集大小)。
- 失败用例保留日志和退出码:
python3 -m pytest -q 2>&1 | tee test.log; echo "exit=$?"。
第五步:接入 CI,让测试自动跑
手工执行三次以上的事情就该进流水线。以 GitHub Actions 为例,每次推送自动在干净的 Ubuntu 容器里复现同一套流程:
name: test
on: [push]
jobs:
test:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- run: pip install -r requirements-test.txt
- run: python -m pytest tests -q --junitxml=report.xml
要点是 CI 里跑的命令必须和本地完全一致(同一个脚本、同一份 compose 文件),否则”CI 是绿的、本地是红的”迟早出现。把 make test 作为唯一入口是最省心的做法。
常见问题 FAQ
Q1:本地 Docker 跑测试和真机结果不一样怎么办?
先对齐三件事:发行版版本、内核相关行为、文件系统类型(macOS 挂载进容器的大小写不敏感是经典坑)。用户态逻辑在容器里高度可信;涉及硬件、内核模块的测试仍需真机或虚拟机。
Q2:测试依赖外部线上接口,跑一次就产生真实数据怎么办?
用 mock 或录制回放替代真实调用:HTTP 层可用 responses/vcrpy(Python)或 wiremock 拦截;实在要联调,为测试单独建隔离的租户或沙箱账号。
Q3:压测应该压多大并发才有意义?
没有普适数字。从预估峰值的 10% 开始阶梯加压,观察响应时间和错误率的拐点,拐点前的最大吞吐就是你的容量基线;超过拐点后的数据用于评估过载表现,而不是容量。
小结
在 Linux 环境下测试的核心不是某个工具,而是”环境可复现、分层快速反馈、结果留痕、流程自动化”这条链路。先用 Docker 固化环境,再按单元→集成→接口→性能的顺序逐层跑,把报告存下来,最后交给 CI——做到这四步,”我本地是好的”就从借口变成了证据。