<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>测试 - tag - 沐木</title><link>https://oldletter.cn/tags/%E6%B5%8B%E8%AF%95/</link><description>测试 - tag - 沐木</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 11 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://oldletter.cn/tags/%E6%B5%8B%E8%AF%95/" rel="self" type="application/rss+xml"/><item><title>工程正确性（一）：测试全绿仍可能违反规格</title><link>https://oldletter.cn/posts/engineering-correctness-01-green-tests-can-be-wrong/</link><pubDate>Sat, 11 Jul 2026 00:00:00 +0000</pubDate><author>mumu</author><guid>https://oldletter.cn/posts/engineering-correctness-01-green-tests-can-be-wrong/</guid><description><![CDATA[<blockquote>
<p>系列导航：<a href="/posts/engineering-correctness-01-green-tests-can-be-wrong/" rel="">11</a> | <a href="/posts/engineering-correctness-02-crypto-interoperability/" rel="">12</a> | <a href="/posts/engineering-correctness-03-database-migrations/" rel="">13</a> | <a href="/posts/engineering-correctness-04-coordinate-precision/" rel="">14</a></p></blockquote>
<p>有一次工具链模块的 Maven 测试达到 110 个通过，构建也显示成功。随后按规格逐项检查，仍发现三个问题：启动 Java 进程时参数被拼成一个字符串，删除镜像请求带了过大的 bearer scope，注册表探测把 <code>401</code> 当成服务可用。测试覆盖了代码路径，却没有覆盖协议的精确定义。</p>
<p>这类问题很难靠继续堆单元测试解决。测试断言、实现和假服务都来自同一份理解时，三者会稳定地一起通过。正确性需要把规格、实现、独立参考和运行行为放在同一张检查表中。</p>
<div class="mermaid" id="id-2" data-mermaid-definition="Zmxvd2NoYXJ0IFRECiAgICBTcGVjW&#43;inhOagvOS4juWNj&#43;iurl0gLS0&#43;IENvbnRyYWN0W&#43;Wlkee6pua4heWNlV0KICAgIENvbnRyYWN0IC0tPiBVbml0W&#43;WNleWFg&#43;a1i&#43;ivlV0KICAgIENvbnRyYWN0IC0tPiBJbnRlZ3JhdGlvblvnnJ/lrp7mnI3liqHlpZHnuqbmtYvor5VdCiAgICBDb250cmFjdCAtLT4gUmV2aWV3W&#43;S6uuW3pei&#43;ueeVjOWuoeafpV0KICAgIFVuaXQgLS0&#43;IEV2aWRlbmNlW&#43;W3ruW8guS4juivgeaNruWMhV0KICAgIEludGVncmF0aW9uIC0tPiBFdmlkZW5jZQogICAgUmV2aWV3IC0tPiBFdmlkZW5jZQogICAgRXZpZGVuY2UgLS0&#43;IEdhdGVb5Y&#43;R5biD6Zeo56aBXQ==">flowchart TD
    Spec[规格与协议] --&gt; Contract[契约清单]
    Contract --&gt; Unit[单元测试]
    Contract --&gt; Integration[真实服务契约测试]
    Contract --&gt; Review[人工边界审查]
    Unit --&gt; Evidence[差异与证据包]
    Integration --&gt; Evidence
    Review --&gt; Evidence
    Evidence --&gt; Gate[发布门禁]</div><h2 id="绿灯的含义要写清">绿灯的含义要写清</h2>
<p>单元测试通过表示输入和断言范围内的函数行为符合预期。它不自动证明参数序列化符合命令行语义，不证明权限范围足够窄，也不证明第三方服务对状态码的解释正确。构建成功只说明编译、打包和被启用的测试任务完成，项目默认跳过测试时尤其要显式检查 <code>-DskipTests=false</code>。</p>
<p>每个关键规则写成可观察的证据：命令行参数保存为参数数组，删除操作的 scope 断言为 <code>pull,push</code> 以外的权限被拒绝，注册表探测把 <code>401</code> 分类为“服务响应但需要认证”，而非健康。断言越接近协议字段，错误越容易被定位。</p>
<h2 id="从规格拆检查项">从规格拆检查项</h2>
<p>先把规格拆成输入、输出、状态码、权限、超时和副作用。实现审查逐项标记证据来源：标准测试向量、第三方服务响应、独立实现、日志或运行截图。没有证据的项保持未验证，不用“已有测试”代替。</p>
<p>接口测试使用真实 HTTP 或接近真实的契约服务器，fake 只模拟网络异常和固定响应。fake 必须拒绝真实服务会拒绝的输入，接受范围过宽会掩盖参数错误。对 CLI、JNI、浏览器和数据库边界，至少准备一组字节或命令行级别的断言，不能只测高层对象。</p>
<h2 id="性质和变形测试">性质和变形测试</h2>
<p>算法或数据处理难以枚举期望值时，加入性质测试：排序保留元素多重集合，金额拆分总和守恒，状态转换不跳过必需阶段，签名篡改后验签失败。变形测试对输入做允许的变换，再检查输出关系，能覆盖示例测试没有触及的组合。</p>
<p>随机测试保存固定反例和生成器版本。只保存随机种子会因生成器改变而无法重现。失败样本缩减后进入回归集，回归集再由人工确认业务含义。</p>
<h2 id="代码通过后的协议复核">代码通过后的协议复核</h2>
<p>复核要跳出实现本身，逐项对照规格检查四个问题：</p>
<ol>
<li>参数是否按对方解析方式传递，尤其是字符串、数组和空值。</li>
<li>权限是否只申请当前操作必需的范围，错误码是否被正确分类。</li>
<li>成功响应是否真的产生了预期副作用，失败是否留下部分状态。</li>
<li>文档、测试、运行配置和打包产物是否描述同一行为。</li>
</ol>
<p>这一步发现的差异不应直接归类为“测试不稳定”。如果规格修正了预期，保留差异报告、旧行为、变更原因和迁移影响。零差异不是目标，未解释的差异才是发布阻断项。</p>]]></description></item></channel></rss>