资讯动态

Python TDD 货币类测试断言失败?用 TaoToken 让 Codex 查

发布时间:2026/9/17 0:12:36 来源:尧图企业网站定制
1. unittest 报错现场test_mixed_addition 的 15 ! 10 不是汇率没写是链路没对上用 unittest 跑 Python TDD 货币类时test_mixed_addition抛出AssertionError: 15 ! 10很常见明明写了bank.addRate(CHF, USD, 2)reduce(bank, USD)却像没看见汇率把 10 CHF 当成 10 USD 直接加。遇到这种报错先把 Codex 接到 TaoToken打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 创建 Key把 Base URL 填成 https://taotoken.net/api 再把完整 traceback 贴给 Codex让它对照Bank.addRate、Bank.rate、Money.reduce、Sum.reduce逐层梳理断言。TaoToken 在这里只提供 Key 和兼容通道货币运算仍然由你的 Python 代码执行。原始文章第 17 章做的是货币类开发回顾从Dollar.times的乘法测试到Franc、Money.plus、Sum.reduce、Bank.addRate的多币种加法。TDD 流程里的伪实现、三角测量、显式实现、消除重复、测试控制力都会在排障时重新出现。区别在于平时写测试是顺着流程往前推报错时是逆着链路往回查。Codex 适合做后者的“对照器”你给它测试、实现、报错它帮你把三条信息摆到同一张桌子上。1.1 报错长这样AssertionError: 15 ! 10先看一个最小测试。它和 17.2 的综合回顾测试同类只是拆得更小方便把问题钉在某一层。import unittest class TestMixedAddition(unittest.TestCase): def test_mixed_addition(self): bank Bank() bank.addRate(CHF, USD, 2) five_dollars Dollar(5) ten_francs Franc(10) result five_dollars.plus(ten_francs).reduce(bank, USD) self.assertEqual(result.amount, 10) self.assertEqual(result.currency, USD) if __name__ __main__: unittest.main()当Bank.rate没有从rates里取到(CHF, USD)默认返回 1。于是ten_francs.reduce(bank, USD)得到 10 USDfive_dollars.reduce(bank, USD)得到 5 USDSum.reduce一加就是 15。断言左边 15右边 10报错为AssertionError: 15 ! 10。这个报错最有迷惑性的地方是程序不崩只是结果偏大。如果addRate根本没执行或者键写成了(USD, CHF)默认汇率 1 会安静地兜底。你看到的是断言失败不是 KeyError所以容易先去改期望值而不是查汇率表。1.2 把 17.2 的 Bank、Money、Sum 链路画成三层排障时不要一上来就改assertEqual。先画链路Bank.addRate(from_currency, to_currency, rate)把汇率写进self.rates[(from_currency, to_currency)]。Bank.rate(from_currency, to_currency)同币种返回 1否则self.rates.get((from_currency, to_currency), 1)。Money.reduce(bank, to)取bank.rate(self.currency, to)然后Money(self.amount / rate, to)。Sum.reduce(bank, to)分别 reduce 加数和被加数再构造新的Money。Bank.reduce(source, to)判断source是Sum还是Money走对应分支。对应代码可以压缩成下面这段。注意它是改写版不是原文批注。class Expression: def reduce(self, bank, to): raise NotImplementedError class Money(Expression): def __init__(self, amount, currency): self.amount amount self.currency currency def plus(self, addend): return Sum(self, addend) def times(self, multiplier): return Money(self.amount * multiplier, self.currency) def reduce(self, bank, to): rate bank.rate(self.currency, to) return Money(self.amount / rate, to) class Sum(Expression): def __init__(self, augend, addend): self.augend augend self.addend addend def reduce(self, bank, to): left self.augend.reduce(bank, to).amount right self.addend.reduce(bank, to).amount return Money(left right, to) class Bank: def __init__(self): self.rates {} def addRate(self, from_currency, to_currency, rate): self.rates[(from_currency, to_currency)] rate def rate(self, from_currency, to_currency): if from_currency to_currency: return 1 return self.rates.get((from_currency, to_currency), 1) def reduce(self, source, to): if isinstance(source, Sum): amount source.augend.reduce(self, to).amount source.addend.reduce(self, to).amount return Money(amount, to) if isinstance(source, Money): rate self.rate(source.currency, to) return Money(source.amount / rate, to) raise TypeError(unsupported expression)Dollar和Franc只负责在构造时指定币种class Dollar(Money): def __init__(self, amount): super().__init__(amount, USD) class Franc(Money): def __init__(self, amount): super().__init__(amount, CHF)这时再回头看15 ! 10排查顺序就很清楚rates里有没有(CHF, USD)rate(CHF, USD)返回 2 还是 1Money.reduce用的是除法还是乘法Sum.reduce有没有把两个金额都转到目标币种四问里任何一问答错断言都会偏。1.3 先让 Codex 查链路不要直接改断言把报错、测试、实现三段一起贴给 Codex效果比只贴一句“为什么断言失败”好得多。你可以用这样的提问模板我在跑 Python TDD 货币类的 unittest报错如下 AssertionError: 15 ! 10 测试代码 [粘贴 test_mixed_addition] 相关实现 [粘贴 Bank.addRate、Bank.rate、Money.reduce、Sum.reduce] 请先解释 10 CHF 在 reduce(bank, USD) 时应该走哪条路径 再指出是汇率没添加、查表键顺序不对、reduce 方向写反还是期望值写错。 不要直接改断言先给我最小修改方案和需要补充的测试用例。Codex 接到这段后通常先指出addRate(CHF, USD, 2)表示 1 USD 对应 2 CHF所以 CHF 转 USD 要除以 2。如果Bank.rate查询键写反默认 1 就会让 10 CHF 变成 10 USD。它还会提醒你补一个test_franc_to_usd_reduce单独验证Franc(10).reduce(bank, USD).amount 5这样下次报错时能更快定位是加法层还是汇率层。2. 把 Codex 的 ~/.codex/config.toml 指到 TaoToken 兼容通道2.1 打开官网创建 Key模型 ID 以模型广场为准Codex 要能回答上面的 Python TDD 报错先得能发出请求。打开 TaoToken 注册并创建 API KeyKey 用占位符YOUR_API_KEY表示。创建完别急着抄旧文章里的模型名模型 ID 以 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 模型广场当时列表为准。官网落地页用于注册、创建 Key、看模型广场、看用量填进 Codex 的 Base URL 是 https://taotoken.net/api 末尾不要带/v1。这两类地址不要混https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end是给人点的用来管理 Keyhttps://taotoken.net/api是给工具填的用来发请求。把 UTM 参数加到 Base URL 上或者把/v1拼到 API 地址后面都可能让 Codex 请求路径异常。2.2 写 ~/.codex/config.tomlmodel_provider 和 base_urlCodex 的配置在~/.codex/config.toml。核心是声明一个自定义 provider并把base_url指到 TaoToken 兼容通道。下面这份可以直接复制后改占位符model YOUR_MODEL_ID model_provider taotoken [model_providers.taotoken] name TaoToken base_url https://taotoken.net/api env_key TAOTOKEN_API_KEY然后在终端里导出 Key。macOS 或 Linuxexport TAOTOKEN_API_KEYYOUR_API_KEYWindows PowerShell$env:TAOTOKEN_API_KEYYOUR_API_KEY注意Codex 不要套ANTHROPIC_*环境变量那是 Claude Code 的写法。Codex 走model_provider和base_urlKey 通过env_key指定的变量读取。模型 ID 换成你在模型广场选中的那个不要凭空写一个带日期后缀的名字。2.3 启动 Codex确认它读的是哪个 provider保存~/.codex/config.toml后在终端运行codex启动日志里会显示当前 model 和 provider。如果仍然显示旧的 provider检查三件事config.toml是不是放在~/.codex/下model_provider的值和[model_providers.taotoken]的节名是否一致env_key对应的环境变量是否真的导出到了当前 shell。排障时不要把 Key 直接写进config.toml提交到仓库用环境变量更稳。3. 把 17.2 的 Bank.addRate/reduce 代码和 traceback 一起丢给 Codex3.1 提问模板报错、测试、实现三段式只贴报错Codex 只能猜。贴全三段它才能对照。推荐格式报错 AssertionError: 15 ! 10 测试 def test_mixed_addition(self): bank Bank() bank.addRate(CHF, USD, 2) five_dollars Dollar(5) ten_francs Franc(10) result five_dollars.plus(ten_francs).reduce(bank, USD) self.assertEqual(result.amount, 10) 实现 class Bank: ... class Money(Expression): ... class Sum(Expression): ... 问题 请对照 17.2 的 Bank.addRate/reduce 链路 判断 10 CHF 在转换为 USD 时是走 Money.reduce 还是 Sum.reduce 以及默认汇率 1 是否掩盖了 addRate 键顺序错误。这样问Codex 会先检查rates字典的键。如果键是(CHF, USD)bank.rate(CHF, USD)返回 2如果键写成了(USD, CHF)get((CHF, USD), 1)返回默认 1。默认 1 就是排障里最容易忽略的“沉默分支”。3.2 Codex 对照 17.2 的 reduce 方向CHF 转 USD 是除以汇率在货币类里汇率方向比代码缩进更容易错。addRate(CHF, USD, 2)的含义是1 USD 可以换 2 CHF。那么 10 CHF 换成 USD应该是10 / 2 5。如果写成10 * 2 20five_dollars.plus(ten_francs).reduce(bank, USD)会得到 25断言报25 ! 10。如果addRate根本没生效默认汇率 1结果就是 15。Codex 在回答时最好让它输出一张路径表而不是直接给最终代码。比如步骤输入调用期望输出1Franc(10)Money.reduce(bank, USD)rate2返回Money(5, USD)2Dollar(5)Money.reduce(bank, USD)同币种 rate1返回Money(5, USD)3Sum(Dollar, Franc)Sum.reduce(bank, USD)5 5 Money(10, USD)4断言result.amount10如果第 1 步的输出是 10说明bank.rate(CHF, USD)返回了 1。接着查addRate的键或者查Money.reduce是否写成了乘法。这个顺序比反复改断言有效。3.3 伪实现、三角测量、显式实现的排障顺序原文 17.3 提到 TDD 里的伪实现、三角测量和显式实现。排障时也能用这套节奏。先让测试跑起来把times或reduce临时写成伪实现确认 unittest 环境没问题再补三角测量用例比如Franc(5).reduce(bank, USD)、Franc(10).reduce(bank, USD)、Franc(20).reduce(bank, USD)看结果是不是分别 2.5、5、10最后把伪实现替换成显式实现并删掉重复代码。Codex 可以帮你生成这些用例但执行python -m unittest的仍然是你。不要让它直接连接业务库或生产机器也不要把货币运算交给它“执行”。它只做代码解释、生成测试、对照断言。你本地跑完把新的 traceback 再贴回对话这样一轮一轮收敛。4. 排障CHF/USD 汇率方向、Money.times 返回值、断言期望值4.1 test_mixed_addition 的 10、15、25 分别代表什么混合加法断言失败常见结果有三种。把它们的含义列出来比盯着assertEqual改数字有用。实际结果可能原因bank.rate(CHF, USD)10 CHF 转 USD15addRate没写或键顺序不对默认 11025reduce写成乘法或反向汇率2 但方向反2010汇率键和 reduce 方向都正确25如果报错是15 ! 10优先查self.rates里到底有没有(CHF, USD)。如果报错是25 ! 10优先查Money.reduce里是self.amount / rate还是self.amount * rate。如果报错是10.0 ! 10那只是整数除法变成了浮点修断言或统一类型即可不是汇率逻辑错。4.2 test_dollar_multiplicationtimes 返回 Money 还是数字乘法测试比加法测试短但坑更隐蔽。原文 17.2 里有def test_dollar_multiplication(self): five_dollars Dollar(5) result five_dollars.times(3) self.assertEqual(result.amount, 15) self.assertEqual(result.currency, USD)如果times写成def times(self, multiplier): return self.amount * multiplierresult是整数 15。第一条result.amount会直接抛AttributeError: int object has no attribute amount根本走不到断言比较。如果times返回Money(self.amount * multiplier, self.currency)但currency因为继承或构造参数写错变成了None第二条断言会报None ! USD。Codex 排障时会先问“result的类型是什么”再问“Dollar构造后currency是什么”。你可以直接在本地加一个临时打印result five_dollars.times(3) print(type(result), result) print(getattr(result, amount, None), getattr(result, currency, None))把输出贴给 Codex比只描述“乘法测试不过”准确得多。4.3 401、404、多了 /v1 在 Codex 配置里的表现Codex 配 TaoToken 时报错不一定来自 Python而来自请求层。本篇可能遇到的是401 UnauthorizedTAOTOKEN_API_KEY没有导出或者 Key 复制时带了空格。404 Not Found模型 ID 不在模型广场当时列表里或者 provider 的base_url写成了带/v1的路径。路径重复base_url https://taotoken.net/api/v1加上客户端自动拼的路径可能出现/api/v1/v1/...。本篇统一用https://taotoken.net/api末尾不加/v1。这些错误和货币断言失败要分开处理。先确认 Codex 能正常回一条消息再让它分析 Python TDD 报错。否则你会在“模型没连上”和“汇率写错了”之间来回怀疑。5. 验证在 Codex 里跑一轮最小 TDD 对话再去控制台看这次调用5.1 用模型对话发一条最小请求配置保存后先在 TaoToken 模型对话 里用同一把 Key 发一条测试消息确认模型 ID 和 Base URL 没填错。这一步能排除 Key 和模型选型问题。如果模型对话都失败Codex 端大概率也失败先回~/.codex/config.toml检查model_provider、base_url、env_key三处。5.2 让 Codex 生成最小修改再本地跑 unittest在终端运行codex把 3.1 的提问模板贴进去。Codex 返回修改建议后你在本地执行python -m unittest test_currency.py -v如果测试文件名不是test_currency.py换成你的实际文件名。重点看test_mixed_addition和test_dollar_multiplication是否都通过。把新的 traceback 贴回 Codex继续让它对照Bank.addRate、Bank.rate、Money.reduce、Sum.reduce。不要让它直接改断言期望值来“通过”那只是把问题藏起来。5.3 去控制台看这次调用是否记上账测试通过后打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 看控制台用量确认这次 Codex 对话记到了正确的 Key 上。如果你同时配了 Claude Code、Codex、CC Switch几把 Key 混用会让用量归属很难查。排障阶段最好一把 Key 对应一个工具等稳定后再统一管理。6. 收尾把模型对话、Coding Plan、Claude Code 文档放进工作流6.1 长期写 TDD 测试Key 和套餐分开管偶尔查一次AssertionError模型对话够用。每天用 Codex 跑 TDD 循环可以看 Coding PlanKey 在 控制台 API Keys 创建和轮换。货币类这种小项目测试文件、实现文件、报错日志分开贴Codex 的定位会更准。6.2 想换 Claude Code 时配置文件别照抄 CodexClaude Code 的环境变量是ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL对应文档在 Claude Code 接入文档。Codex 用~/.codex/config.toml两者不要混。尤其是 Base URL填进工具的一律是https://taotoken.net/api末尾不加/v1。排障时最有用的是把 traceback、测试、实现三段一起给 Codex让它先解释路径再改最小代码。货币运算还是你的 Python 代码在跑unittest也是你本地执行。下次再看到15 ! 10先查Bank.addRate的键再查Money.reduce的方向最后才看断言期望值。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价