Claude Code 三系统实用教程:用契约测试完成开发、调试与会话恢复

Claude Code 改完代码后,终端返回 1,究竟是程序坏了,还是程序正确地找到了坏数据?如果事先没有定义退出码,工具很容易沿着错误方向继续修改。

本文从这个具体问题展开:安装与登录后,让 Claude Code 实现一个小型 JSONL 检查器,再用独立测试判断交付。最后区分继续会话、回退代码和恢复数据,避免把它们混成同一种“撤销”。

一、Windows、macOS、Linux 的安装与更新

以下于 2026-09-20 对照 Anthropic 安装文档 核查。macOS、Linux、WSL 在对应终端执行:

curl -fsSL https://claude.ai/install.sh | bash

Windows 原生 PowerShell:

irm https://claude.ai/install.ps1 | iex

当前原生安装方式支持自动更新,也可执行 claude update 主动更新。用 Homebrew 或 WinGet 安装的,应按原包管理器更新;不要把几种渠道同时堆进 PATH。

Windows 原生环境推荐配合 Git for Windows;当前文档也说明未找到 Git Bash 时可使用 PowerShell。需要 Linux 工具链可使用 WSL 2,并在 WSL 内单独核对安装、目录和 Python。Claude Code 原生 Windows 的沙盒支持与 Codex 不相同,不能把另一工具的说明直接搬过来;当前内置沙盒不支持原生 Windows,WSL 2 是相应选择之一。

安装后新开终端:

claude --version
claude doctor

找不到命令时,Windows 用 Get-Command claude,macOS/Linux 用 command -v claude 看实际位置;claude doctor 用于检查安装及配置状态。

二、进入项目并登录

新建空目录 jsonl-lab,进入目录执行 claude,根据界面选择适用账号并完成登录。会话内可用 /login 重新认证;如果环境已经设置 ANTHROPIC_API_KEY,登录流程可能先询问是否使用该密钥。本文不需要把密钥写进代码。参见 官方快速开始

先让工具说明当前目录、已有文件和运行 Python 3 的命令。本文示例只依赖 Python 标准库。Windows 常用 py -3,macOS/Linux 常用 python3,都要先检查版本是否可用。

项目根目录建立 CLAUDE.md

只实现本练习的 JSONL 校验器,使用 Python 标准库。
输入只读;报告使用新文件名,拒绝覆盖已有报告。
修改前说明计划,发现规格冲突先指出具体冲突。
不要为了通过测试而删除断言或放宽数据校验规则。
检查失败时先读错误和契约,再决定改实现还是纠正规格。
最后报告实际测试命令、退出码、结果及未验证事项。

这些内容帮助模型理解项目,不能替代权限控制。确认操作范围后再允许具体命令,不需要为入门练习开启跳过权限确认的模式。

三、先定义任务与五项契约测试

给 Claude Code 下面这段任务,再把后面的测试保存为 test_contract.py

先阅读 test_contract.py,然后说明计划并实现 audit_jsonl.py。
提供 audit(text) 函数,返回 valid、invalid、errors。
每个非空物理行是一个 JSON 对象;空行忽略但行号保留。
id 和 text 必须为去除两端空白后非空的字符串。
ID 去空白后判重,仅此前有效记录占用 ID。
错误顺序为 invalid_json、not_object、invalid_id、invalid_text、duplicate_id。
每条坏记录仅记一项错误,errors 中只记录 line 和 code。
JSON 重复键及 NaN、Infinity 等非标准常量都按 invalid_json 处理。
CLI 接收输入路径及 --output 参数;按 UTF-8 读取并兼容开头 BOM。
不修改输入,拒绝覆盖已有报告。
全部有效退出 0;有坏数据且报告写出退出 1;文件或参数错误退出 2。
先运行已有契约测试,再补空文件、非法编码、重复 JSON 键等边界检查。
不要把退出码 1 擅自改成 0。

以下五项测试可以完整运行;假定实现文件与测试在同一目录:

import json
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
from audit_jsonl import audit


class ContractTests(unittest.TestCase):
    def test_duplicate_id(self):
        data = '{"id":"a","text":"甲"}\n{"id":" a ","text":"乙"}'
        self.assertEqual(audit(data)['errors'],
                         [{'line': 2, 'code': 'duplicate_id'}])

    def test_bad_record_does_not_reserve_id(self):
        data = '{"id":"a","text":""}\n{"id":"a","text":"ok"}'
        self.assertEqual(audit(data)['valid'], 1)

    def test_physical_line(self):
        self.assertEqual(audit('\nwrong')['errors'][0]['line'], 2)

    def test_unicode_separator(self):
        data = json.dumps({'id': 'a', 'text': '甲\u2028乙'}, ensure_ascii=False)
        self.assertEqual(audit(data)['invalid'], 0)

    def test_cli_and_no_overwrite(self):
        with tempfile.TemporaryDirectory() as folder:
            source = Path(folder) / '输入 sample.jsonl'
            report = Path(folder) / 'report.json'
            original = b'{"id":"a","text":"ok"}\nbroken\n'
            source.write_bytes(original)
            command = [sys.executable,
                       str(Path(__file__).with_name('audit_jsonl.py')),
                       str(source), '--output', str(report)]
            first = subprocess.run(command, capture_output=True, text=True)
            self.assertEqual(first.returncode, 1)
            self.assertEqual(first.stdout.strip(), 'valid=1 invalid=1')
            saved = report.read_bytes()
            self.assertEqual(json.loads(saved)['errors'],
                             [{'line': 2, 'code': 'invalid_json'}])
            second = subprocess.run(command, capture_output=True, text=True)
            self.assertEqual(second.returncode, 2)
            self.assertEqual(report.read_bytes(), saved)
            self.assertEqual(source.read_bytes(), original)


if __name__ == '__main__':
    unittest.main()

测试把输入路径放在临时目录中,包含中文和空格;通过参数列表调用 Python,不靠拼接 shell 字符串。它既检查函数规则,也检查真实 CLI、退出码、已有报告和输入字节。

Windows 运行:

py -3 -m unittest -v test_contract.py

macOS/Linux 运行:

python3 -m unittest -v test_contract.py

本次参考实现先通过了 17 个 unittest 方法;从验收需求另整理的上面五项测试也已单独运行通过,包含与原测试重叠的检查,不把它们算成 22 个独立场景。环境是 macOS arm64、Python 3.13.13。本轮未安装或运行 Claude Code 模型会话,三系统安装步骤来自当日官方文档。

四、失败时让工具围绕证据修复

如果 test_unicode_separator 失败,先让它解释:字符串里的 U+2028 为什么被切成了另一条 JSONL 记录。问题可能是用了 splitlines(),而我们的契约只按物理 LF 换行拆记录。

如果真实 CLI 测试返回 0,要核对“有坏记录也成功生成报告”应该返回哪个状态,不要因为终端没有 traceback 就认定正确。

可追加提示:

只处理当前失败的契约。先指出实际值和预期值的差异,
解释根因,再做最小修改。保留原断言,重新运行相关测试,
通过后运行全部测试。说明输入文件和已有报告是否仍保持原样。

测试也可能写错,所以“保留断言”不代表绝对禁止调整;真正冲突时,应先讲清需求为何变化,再同步实现、测试和文档。不能在不说明的情况下悄悄降低标准。

五、继续会话不等于回退磁盘

在项目目录执行 claude -c 可继续当前目录最近会话;claude -r 用于选择历史会话。回到对话后,让工具先读最新文件与测试结果,再继续计划。

需要检查点菜单时,在会话使用 /rewind,或在输入为空时连按两次 Esc。菜单可以选择恢复代码、恢复对话或两者。关键限制是:检查点主要跟踪 Claude 文件编辑工具的直接修改,Bash 命令造成的文件变化不在这套回退范围内。参见 检查点官方说明

本例运行 Python 产生的报告属于命令执行的输出,不能假定回退会自动清除或还原它。恢复会话后再次运行相同报告名,程序拒绝覆盖是预期行为;指定新报告名即可保留两次结果。

Git 版本记录、文件备份、数据库事务各有自己的职责。不要因为菜单上有“恢复代码”,就推断数据库和远程服务也会回到原状。

六、AGENTS.md 是否需要再复制一份

今天核查的文档已经给出直接读取 AGENTS.md 的支持:要求 Claude Code v2.1.277 或更高,并受会话环境及项目指令配置影响。默认情况下,工作目录或上级已有 CLAUDE.md / CLAUDE.local.md 时,会优先读这些文件;不能仅因两个文件都存在就认为二者都已加载。

某些会话(例如特定第三方提供商或禁用遥测时)不支持直接读取;已有 CLAUDE.md 导入 @AGENTS.md 的兼容做法仍可保留。请对照 项目记忆文档 检查自己版本与会话。本例直接使用 CLAUDE.md,便于明确项目规则。

完整工作流应有实际输入、独立验收和恢复边界。先用小项目走通这些环节,再增加插件或复杂编排,调试时才知道问题来自哪一层。

本文使用 AI 辅助整理与编写;只把有记录的离线 Python 检查称为实测,不把官方功能说明写成个人模型使用经历。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值