
想靠刷题学好测试天花板很低。我接触过不少想转测试或者刚入行的朋友最容易卡在同一个环节教程里的接口测试、性能测试都看了一碰到真实系统就不知道怎么下手。后来我带人练手发现拿一个开源项目当靶子是最快的路子。这里面我特别推荐 SkyWalking——它不是“又一个要学的工具”而是一个天然适合被测试的分布式链路追踪系统。围绕它做测试学习你能把功能测试、接口测试、性能测试、异常测试、自动化回归练一个遍而且每一步都能看到直接的成果反馈。这篇文章就给你梳理一套完整的 SkyWalking 测试学习思路从环境搭建到用例设计再到常见坑位照着做基本能少走两三个月的弯路。1. 为什么拿 SkyWalking 当测试学习靶子1.1 一个项目覆盖了多种测试类型SkyWalking 本身不是个小玩具它包含 Java Agent 探针、OAP 分析平台、Web UI、存储后端默认 ES这几大块。你用测试视角去看它其实是一个“带完整前后端和数据通道的系统”可测的面非常多功能层面UI 上的拓扑图、链路查询、指标看板、告警规则接口层面OAP 的 GraphQL 查询接口、gRPC 上报接口性能层面Agent 对业务应用的额外开销、OAP 在高并发流量下的处理能力数据层面Trace、Segment、Span 是否丢失、结构是否完整、时间戳是否合理异常层面Agent 挂了怎么办、OAP 重启后数据能不能补、存储不可用是什么表现。对于学习测试的人来说最大的好处是“问题可观察、结果可验证”。你发一笔请求过几秒去 UI 上就能查链路写错了、漏了肉眼可见。这种反馈速度是刷一百道面试题都给不了的。1.2 链路追踪系统的测试难点数据对不对链路追踪系统和普通 Web 系统的测试思路有很多不同。普通系统你测的是“接口回没回、状态码对不对”而 SkyWalking 这类系统核心难点是数据经过一条很长管道后的完整性业务服务产生 trace - Agent 采集 - gRPC 批量上报 - OAP 分析聚合 - 写入 ES - UI 查询展示。这里头每一步都可能有数据缺失或变形。gRPC 是批量上报的OAP 是按窗口做聚合的ES 写入有延迟UI 查询有分页限制。所以测试时不能只看界面好不好看而是要设计“数据对账”的用例预先知道发送了多少请求、产生了多少 span查询的时候核对数量有没有少、父子关系对不对。这种“设计校验口径”的能力恰恰是很多测试新人最缺的也是找工作时最容易拉开差距的地方。1.3 通过它你能练到的测试技能我把通过 SkyWalking 能练到的技能和对应的实践点整理成一个表方便你对照着做学习规划技能方向对应实践点接口测试调用 OAP 的 GraphQL 接口查 trace、查指标写断言自动化测试用 Python / 脚本完成造数、查询、校验、报告性能测试用 JMeter 压 OAP对比业务应用加不加 Agent 的 RT 差异数据测试检查 span 数量、时间戳、traceId 串联、拓扑关系异常测试kill 掉 OAP、停 ES、模拟 Agent 上报超时兼容性测试换存储后端、换版本组合验证系统表现这套技能树搭下来不是“会点 JMeter 名词”的程度是真正能上手干活的程度。2. 搭一个“最小可测系统”先跑通一条链路2.1 被测系统架构拆解你手上到底有几个部件要测试一个系统第一步一定不是找工具而是把被测对象的部件摸清楚。SkyWalking 最常见的部署形态里有四个角色Java Agent以-javaagent方式挂到业务应用上用字节码增强技术拦截 HTTP 请求、数据库访问等动作生成 trace 数据。OAP Server负责接收 agent 上报的数据做分析、聚合、告警判定对外提供查询接口。SkyWalking UI一个浏览器端界面把链路和指标可视化。存储后端OAP 将处理后的数据写入 ES也支持 MySQL、BanyanDB 等UI 查询时由 OAP 从存储读数据。端口方面你最好一开始就记牢Agent 上报到 OAP 的 gRPC 默认端口是 11800OAP 对外提供查询的 HTTP 端口是 12800UI 默认跑在 8080。数据模型方面一条用户请求最终形成一棵 trace 树树上有多个 segment 片段——每个服务进程会生成一段 segmentsegment 里包含多个 span。span 又分三种EntrySpan服务入口、ExitSpan发起外部调用、LocalSpan本地逻辑。这些概念不用死记但你造数据、写断言的时候一定会用到比如断言“这次请求产生了两个 segment、三个 span”时得先知道它们分别代表什么。2.2 用 Docker Compose 快速搭环境版本和端口是关键常规的搭建流程网上有很多文章但如果你只是为测试学习做准备我建议直接用 Docker Compose 一把梭把 OAP、UI、ES、一个 demo 服务串起来。下面是一个我调过的简版 Compose 配置版本组合是 SkyWalking 9.x ES7已经实测可跑version: 3 services: es7: image: docker.elastic.co/elasticsearch/elasticsearch:7.17.9 container_name: sw-es7 environment: - discovery.typesingle-node - xpack.security.enabledfalse ports: - 9200:9200 oap: image: apache/skywalking-oap-server:9.6.0 container_name: sw-oap depends_on: - es7 environment: - SW_STORAGEelasticsearch - SW_STORAGE_ES_CLUSTER_NODESes7:9200 - SW_CORE_GRPC_PORT11800 - SW_CORE_REST_PORT12800 ports: - 11800:11800 - 12800:12800 ui: image: apache/skywalking-ui:9.6.0 container_name: sw-ui depends_on: - oap environment: - SW_OAP_ADDRESShttp://oap:12800 ports: - 8080:8080提示网上很多文章会直接docker run单跑 OAP但那样会漏掉 ES 依赖。本地测试至少要把存储和 OAP 放同一套 Compose 里否则 OAP 会一直报 index 不存在。一个最容易踩的坑是版本乱配。SkyWalking 的 Agent、OAP、UI 三者的版本要尽量一致存储的索引结构也跟版本强相关。我见过有人 UI 用的 8.x、OAP 用的 9.x最后页面上一直报查询失败排查半天才发现是版本不匹配。2.3 制造可控的测试数据让调用链“可预期”环境起来之后不能空着练手得有自己的“业务”。我的做法是准备两个 Spring Boot 服务一个 order-service一个 user-service。order 服务在创建订单时会通过 RestTemplate 调用 user 服务查询用户信息这样就能产生一条跨服务的真实调用链。启动时给两个服务各加一段 Agent 参数java -javaagent:/path/to/skywalking-agent.jar \ -Dskywalking.agent.service_nameorder-service \ -jar order-service.jar这样访问一次GET /order/create大约半分钟到一分钟内在 UI 的“拓扑图”页面就能看到 order-service 和 user-service 两个节点的连线链路查询里能看到一个包含两个 segment 的 trace。为什么强调“可控”因为测试用例需要可重复。如果你每次去 UI 上随便点数据毫无规律你没法写断言。造数据控制在两种场景里就够了正常的 200 请求以及故意让某个接口抛异常的 500 请求。前者用来验证链路完整、耗时正常后者用来验证错误链路的状态标记和告警触发。2.4 测试基线先定义“什么算正常”很多新手一上来就看图图有就有没有就觉得“系统坏了”。这不对。你要在写第一条用例之前先定义一个可量化的基线否则后面自动化无从谈起。我用的基线一般是三个维度数量完整一次请求对应一条 trace一个跨服务调用会拆成两段 segment每个 span 都有上游 parentSpanId 串联。结构正确EntrySpan 在最外层ExitSpan 的下游能续接上对端服务的 EntrySpanservice 节点之间有清晰的 client/server 关系。数据合理开始时间、结束时间、耗时是正数且单调递增endpoint 名字与代码路径能对上。这是你自己定的验收口径。搞明白“什么算正常”你才能谈“现在到底有没有 bug”。这也正是测试的核心思维不是把系统点一遍而是先建立预期再去做验证。3. 按测试类型拆解功能、接口、性能、异常3.1 功能测试从 UI 到告警别漏掉边界功能测试是最容易上手、也最容易做“假”的一层。很多人打开页面点两下截图就算测完了这不行。我建议你把 UI 拆成模块写用例拓扑图服务节点和连线是否正确显示服务名是否和 agent 配置一致删除一个服务后图会不会淡出。链路查询按时间范围、按服务名、按 traceId、按 endpoint 筛选组合条件是否生效查询结果分页是否正确。指标看板响应时间、吞吐量曲线是否在请求后出现变化刷新频率和数据窗口是否符合预期。告警列表配置一个“最近 3 分钟成功率低于 80%”的规则然后用脚本打一批 500 请求看告警能不能触发、恢复后会不会自动清除。边界情况是最容易漏的默认时间范围通常是“最近 15 分钟”但如果被测服务刚好在 16 分钟前产生过数据页面就会一片空白新手很容易误判成系统故障。再比如跨天查询很多 UI 组件对跨日期的查询条件处理不好这也是值得记录的一条功能 bug。注意SkyWalking 的 UI 查询结果不是实时的。链路数据从 Agent 采集到 OAP 聚合再到 ES 索引可见会有 30 秒到几分钟的延迟。功能用例里要设计显式等待否则会出现“请求发送成功但 UI 查不到”的假失败。3.2 接口测试直接查 OAP 的 GraphQL 接口UI 上看到的所有图表底层都是 OAP 的 GraphQL 接口。既然要学接口测试那就不该停留在 Postman 打一个 GET 请求的水平而是应该学会向 GraphQL 端点发送结构化查询并做字段级断言。OAP 的 12800 端口暴露了/graphql端点你可以用 Python 直接请求import requests OAP_ENDPOINT http://127.0.0.1:12800/graphql query query queryTraces($condition: TraceQueryCondition) { queryTraces(condition: $condition) { traces { key: segmentId endpointNames duration start isError } } } variables { condition: { queryDuration: { start: 2025-01-01 000000, end: 2025-01-01 235959, step: MINUTE }, traceState: ALL, queryOrder: BY_START_TIME, paging: {pageNum: 1, pageSize: 10} } } resp requests.post(OAP_ENDPOINT, json{query: query, variables: variables}) assert resp.status_code 200 data resp.json() assert errors not in data print(data[data][queryTraces][traces])提示不同版本的 GraphQL Schema 字段可能有差异写脚本前先在 OAP 的/graphql上用自带的文档面板确认字段名。我用的是 9.x 的结构8.x 大体兼容但个别字段会有变动。接口测试的重点不是“调通”而是“断言”。我常用的断言组合状态断言HTTP 200且data节点里没有errors。数量断言返回的 trace 条数不小于预期分页大小为 10 时最多返回 10 条。结构断言trace 里包含两个以上 segment且 segment 之间有父子级联关系。业务断言isError 字段与造数时的 500/200 结果一致。3.3 性能测试既要压 OAP也要测 Agent 的损耗一说到性能测试新手第一反应就是“上 JMeter给系统上压”。但链路追踪系统的性能测试至少要拆成两个方向一个方向是压 OAP 本身的查询能力和写入能力另一个方向是测 Agent 挂在业务应用上带来的额外开销。先看 OAP 这边。你可以用 JMeter 建一个线程组专门打 OAP 的/graphql查询接口。我常用的压测参数是线程数 100Ramp-up 周期 10 秒循环次数 20总共 2000 个请求。请求体就是 3.2 节那个 GraphQL 查询聚合报告里主要看三项平均响应时间、错误率、吞吐量。这个时候你关注的是 OAP 的 CPU、堆内存以及 ES 的写入队列而不是业务应用本身。再看 Agent 损耗。这个测试设计更有意思同样的业务接口在不开 Agent 的情况下压测记录 TPS 和 RT然后在同样条件下开启 Agent再压测一轮对比两个结果。两份数据之间的差就是 SkyWalking 对业务应用的额外开销。场景平均 RTTPS观察项未接 Agent2.1 ms1860基线接入 Agent2.6 ms1520额外开销约 20% 左右这套对比数据在面试或项目汇报里非常好用因为它体现了“测试不是只会点按钮而是能设计实验来量化影响”。如果你发现 Agent 带来的开销异常放大优先检查采样率配置和 Agent 版本。注意性能测试环境要和功能测试环境分开或者保证数据量基线一致。否则 ES 里积累了几十万条历史数据查询性能的压测结果会严重失真。3.4 异常场景与故障注入这组用例最能拉开差距普通功能用例大家都会写真正体现测试水平的是异常场景。做这类测试前一定要准备隔离环境别在给客户演示的机器上随便 kill 进程。下面是我实际跑过的故障注入清单停止 ES 容器OAP 仍然能启动但所有查询接口会报存储错误此时 Agent 照常上报OAP 堆积数据。重启 ES 后堆积的 trace 会被继续写入但期间的数据查询会全部失败。直接 kill OAP 进程Agent 会不断重连gRPC 客户端会在后台持续尝试恢复。把 OAP 重新拉起后Agent 会在几秒内重连成功中间积压的数据会补传上来。我测试时观察到补传窗口大约在 5 到 30 秒之间。模拟 Agent 上报延迟通过防火墙规则或 tc 命令给 11800 端口加延迟观察 Agent 的内存占用是否增长、业务接口 RT 是否因此受影响。手动改动系统时间这个操作比较“脏”但能验证时间戳问题。把测试机器的时间往前调 1 小时再发请求UI 链路查询里会出现排序错乱这也是一个典型的数据正确性 bug。异常用例的关键是记录“预期行为”。比如 “OAP 重启后不再接受 Agent 上报但 Agent 不崩溃、业务不受影响”这就是一条合格的需求描述。把这些用例沉淀成文档比单纯写“XXX 挂了”有价值得多。4. 自动化回归造数据、写断言、接流水线4.1 自动造链路数据模拟多服务调用和异常 trace做自动化回归的第一步是解决“数据从哪来”的问题。手工点接口造数撑不了几次我建议用一段简单的脚本定时向 demo 服务发请求同时随机混入一部分错误请求和慢请求让被测系统里的链路数据保持“有正常、有异常、有慢调用”的状态。import random import time import requests demo_urls [ http://127.0.0.1:8082/order/create, http://127.0.0.1:8082/order/get, http://127.0.0.1:8082/user/info ] for i in range(200): url random.choice(demo_urls) try: if random.random() 0.1: # 10% 概率制造错误请求 requests.post(url ?error1, timeout3) elif random.random() 0.2: # 20% 概率制造慢请求 requests.post(url ?sleep2000, timeout5) else: requests.get(url, timeout3) except Exception as e: print(frequest error: {e}) time.sleep(0.2)这段脚本每次跑完SkyWalking 里就会有一批分布相对固定的 trace 数据足够支撑自动化用例的断言。造数这件事占整个自动化工作量的三成左右但它决定了后面所有用例是否稳定值得认真对待。4.2 一套 Python 接口自动化用例示例接口自动化我推荐用 pytest配合 requests 就够了。用例的逻辑很简单先确认环境里有一定数量的 trace再按条件查询并校验关键字段。下面是一段能直接跑的用例骨架import requests import pytest BASE http://127.0.0.1:12800/graphql def query_traces(page_size5): payload { query: query ($condition: TraceQueryCondition) { queryTraces(condition: $condition) { traces { key endpointNames duration start isError } } } , variables: { condition: { queryDuration: { start: 2025-01-01 000000, end: 2025-01-01 235959, step: MINUTE }, traceState: ALL, queryOrder: BY_START_TIME, paging: {pageNum: 1, pageSize: page_size} } } } resp requests.post(BASE, jsonpayload, timeout5) assert resp.status_code 200 return resp.json() def test_query_traces_success(): data query_traces() assert errors not in data traces data[data][queryTraces][traces] assert len(traces) 0 def test_trace_has_expected_fields(): data query_traces(page_size1) trace data[data][queryTraces][traces][0] assert key in trace assert trace[duration] 0 assert isinstance(trace[isError], bool)运行方式pytest test_skywalking.py -v。这套用例虽然简单但它能保证 OAP 查询接口没有根本性故障适合作为每次版本升级后的冒烟测试。我建议把“硬件检查”也混在自动化里定时调用curl http://127.0.0.1:12800/graphql探活如果返回非 200就自动发一封告警邮件。这样做的好处是你不需要每天手动打开界面确认系统还活着。实战经验断言超时时间不要设得太短。OAP 在首次冷启动或 ES 索引重建期间GraphQL 查询可能长达 5 秒才能返回。如果断言超时设成 2 秒会频繁出现假失败干扰真正的问题排查。我一般设 5 到 8 秒。4.3 断言与基线管理不要用“肉眼看图”代替校验自动化测试最忌讳的一条是跑完脚本后打开 UI 截图“看结果”。这样根本没有起到回归的作用因为人眼很难发现数据量的细微偏差。我的做法是把每次执行后的关键指标存成 JSON作为“基线”下次跑完再和基线做 diff。比如基线文件baseline.json长这样{ query_time: 2025-01-01 00:00:00, total_traces: 128, error_traces: 12, avg_duration_ms: 186, max_duration_ms: 2300, service_count: 2 }测试脚本结束前自动读取当前查询结果和基线对比超过阈值就失败。阈值怎么定我的经验是正常造数脚本跑一轮total_traces 上下浮动不超过 10%error_traces 比例不超过 15%。如果超过这个范围大概率是造数脚本或被测系统出了问题需要人工介入。有了基线管理你才能在做了代码改动、版本升级、配置调整之后快速发现“这次改动是不是影响了链路数据的完整性”。这也是自动化回归真正的价值——不是跑给领导看而是真的能拦住回归问题。4.4 用 JMeter 做并发测试的几个细节JMeter 是压测 OAP 查询接口的常用工具但它有几个细节特别容易踩坑我单独拎出来说第一GraphQL 请求体要用 HTTP 请求采样器发送不要用普通的 GET 参数拼接。完整的 JSON 体放在“Body Data”选项卡里Content-Type 设置为application/json。如果用 CSV 参数化 traceId注意编码格式要选 UTF-8否则中文 endpoint 名可能乱码。第二线程组参数不要盲目学习网上的“1000 并发”。本地测试虚拟机上OAP 的处理能力有限我建议初始参数是线程数 50Ramp-up 5 秒循环 10 次先看基线再逐步上调。你压本地环境的目的不是测出极限值而是学会“如何判断系统接近瓶颈”。第三JSR223 断言中可以直接解析响应里的errors字段判断查询是否成功。光有 HTTP 200 不够GraphQL 的业务错误也在 200 里返回。def json new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString()); if (json.errors ! null) { prev.setSuccessful(false); prev.setResponseMessage(GraphQL errors: json.errors); }这个断言逻辑比默认的“响应代码200”要严格得多能帮你抓住数据层面的异常。5. 技能树横向扩展从链路追踪到测试全栈5.1 深入探针字节码增强与异步场景测试测试学到一定程度你会想往更深处走。SkyWalking 的 Java Agent 用的是字节码增强也就是在类加载时修改方法的执行逻辑把埋点代码织入进去。这种机制带来的测试挑战是不是所有代码路径都会被自动埋点特别是异步线程、消息队列消费、定时任务场景。我建议你有空去读一下 Agent 插件的测试目录里面全是真实场景的测试用例。比如apm-spring-cloud-gateway-plugin插件怎么验证一个请求经过网关转发后trace 上下文还能保持不丢。你不需要读懂每一行源码但至少要理解插件生效的前提是什么依赖包存在且类被加载到特定的 ClassLoader异步线程为什么容易丢链路ThreadLocal 在线程池场景下并不会自动传递这类问题怎么在测试中复现用线程池发异步请求观察 UI 链路是否被切断这些知识点在普通功能测试里永远不会碰到但它们才是链路追踪系统真正有深度的测试场景。学会这几个场景你的测试面试深度会明显上了一个台阶。5.2 交叉练习用类似工具或漏洞平台补盲区没有一种技术是孤立的。SkyWalking 练熟之后我强烈建议你做两件横向扩展的事。第一件事是拿同类工具做对比测试。Zipkin、Jaeger、SkyWalking 都是链路追踪方案但数据模型、采样策略、存储设计完全不同。你可以设计同一份业务负载分别接入三种方案对比它们的埋点完整性、查询响应时间、资源占用差异。这种“横向评测”本身就是一种标准的测试工作做出来就是一份很有分量的技术文档。第二件事是补一下安全测试的基础。想在测试这条路上走得更远安全测试的能力很加分。你可以本地搭一个开源的漏洞靶场比如 pikachu通过它理解 SQL 注入、XSS、越权等常见漏洞的成因和测试思路再回头审视 SkyWalking 的一些接口是否存在类似的参数校验缺陷。整个过程要在自己搭的本地环境里做合法合规。5.3 一个可执行的三个月学习路线最后给一套我的个人节奏你可以按自己的情况微调第 1 周搭好完整环境把一条跨服务的链路跑通。只要能亲自在 UI 上看到 order-service 调 user-service 的 trace就算过关。第 2 周不做 UI 操作所有查询都用 GraphQL 接口来完成。强制自己用脚本代替手工点页面。第 3 周写第一版自动化用例覆盖 trace 查询和字段断言。先跑通 10 条用例再追求数量。第 4 周开始做性能测试记录 OAP 查询接口的基线和 Agent 的开销数据。第 5 周做故障注入测试把 OAP、ES、Agent 三个角色各搞挂一次记录恢复行为和影响范围。第 6 周起把所有用例和基线管理接入本地 CI比如每天定时跑一遍输出一份报告。这个路线没有堆砌概念每一步都是可操作的任务。你如果真的完整走下来对你测试能力的提升会比上两个月网课更明显。我自己的感觉是测试学习最有用的东西不是某个工具而是建立“系统思维”。SkyWalking 恰好是一面很好的镜子它把请求的来龙去脉拆得清清楚楚理解它之后你再看其它分布式系统会自然带着“这条数据从哪来、到哪里去、丢了怎么发现”的视角去看这才是真的收获。关于时间的校验我一直建议测试机装 NTP 同步。链路追踪最怕的就是机器时钟偏了一旦偏了trace 时间线乱成一团排查起来极容易误判。所以最后再分享一个小技巧每次搭测试环境时先跑一下date确认时间正常这能省下你后面大量的排查时间。