确定性断言与代码测试
正在读取学习记录…
确定性断言是一条可以由程序重复判断的条件:同样的输入和状态,每次都应得到同样的真假结果。退款助手回复“已成功退款”以后,系统可以检查订单号是否正确、金额是否为100元、账本是否真的新增一笔退款。
这像交货验收:包装完整只是第一关,还要核对收货人、数量和实际到货。把所有检查压成一句“看着挺好”,一旦失败,既找不到原因,也容易让漂亮的包装蒙混过关。
正常退款需要四份明确条件
订单 order-1 属于 user-a,已支付100元。任务要求全额退款一次。正常输出带五个字段:status 是refunded,order_id 是目标订单,owner 是当前用户,amount 是整数100,receipt 是退款回执编号refund-1。账本中还应有且只有一笔目标订单的退款,内容与回执对应。
先把要求拆成四项。structure 检查结构:字段、类型与状态值。ownership 检查订单和用户是否匹配原单。amount 检查是否退了应退的100元。effect 检查账本中的事务效果是否存在、唯一,并与输出一致。总体通过要求四项同时满足。
“效果存在”与“业务正确”可以分别失败:退给另一用户的记录可能真实存在,所以effect通过,但ownership失败。若退款金额是90元且账本也记90元,effect通过,amount仍然失败。细分检查能保留这类差异。
代码断言适合检查什么
字段类型、可枚举状态、数值边界、已有数据库记录都适合写成代码。回答是否体贴、解释是否清晰等开放质量,往往还需要有明确Rubric的评审。确定性是评分器的重复性;被测模型可以每次产生不同输出,评分器仍对每份输出按同一规则检查。
下面程序用五组预置输出与账本快照运行评分器。它依次展示正常、错用户、错金额、缺效果和重复效果。账本在例子中是一份列表,便于读懂“找目标订单的一笔事务”这件事;实际系统可以把读取接口接到测试数据库或可核查的退款回执。
从空目录保存并运行
在 PowerShell 中进入你平时使用的学习目录,再创建本节文件夹并进入:
mkdir l7-assertions
cd l7-assertions用编辑器新建文件,把下面完整代码保存为当前文件夹的 assertions_lab.py。保存类型选“所有文件”,编码选 UTF-8;资源管理器开启“文件扩展名”,核对文件名以 .py 结尾。数据已经写在代码里,可以直接运行。
"""对退款结果分别检查结构、归属、金额和实际账本效果。"""
from copy import deepcopy
ORDER = {"order_id": "order-1", "owner": "user-a", "paid": 100}
GOOD = {"status": "refunded", "order_id": "order-1", "owner": "user-a",
"amount": 100, "receipt": "refund-1"}
LEDGER = [{"receipt": "refund-1", "order_id": "order-1", "owner": "user-a", "amount": 100}]
def grade(output, ledger):
"""每个布尔结果对应一条明确契约,最终通过要求全部满足。"""
fields = {"status", "order_id", "owner", "amount", "receipt"}
structure = (isinstance(output, dict) and set(output) == fields
and output.get("status") == "refunded"
and all(type(output.get(key)) is str and output[key].strip()
for key in ("order_id", "owner", "receipt"))
and type(output.get("amount")) is int)
# 先守住结构;后续每项独立给出结果,避免KeyError遮住真正问题。
belongs = structure and output["order_id"] == ORDER["order_id"] and (
output["owner"] == ORDER["owner"])
amount = structure and output["amount"] == ORDER["paid"]
# 查整笔事务的行数和内容,重复退款不能因找到一条匹配记录而通过。
matching = [row for row in ledger if row.get("order_id") == ORDER["order_id"]]
effect = (structure and len(matching) == 1
and matching[0] == {key: output[key]
for key in ("receipt", "order_id", "owner", "amount")})
checks = {"structure": bool(structure), "ownership": bool(belongs),
"amount": bool(amount), "effect": bool(effect)}
return checks, all(checks.values())
def scenarios():
"""固定五种结果;每种错误只改变一个业务因素。"""
return [
("good", deepcopy(GOOD), deepcopy(LEDGER)),
("wrong-owner", dict(GOOD, owner="user-b"),
[dict(LEDGER[0], owner="user-b")]),
("wrong-amount", dict(GOOD, amount=90), [dict(LEDGER[0], amount=90)]),
("missing-effect", deepcopy(GOOD), []),
("duplicate-effect", deepcopy(GOOD), deepcopy(LEDGER + LEDGER)),
]
def main():
for name, output, ledger in scenarios():
checks, passed = grade(output, ledger)
detail = " ".join(f"{key}={'通过' if value else '失败'}"
for key, value in checks.items())
print(f"{name}: {detail} 总体={'通过' if passed else '失败'}")
if __name__ == "__main__":
main()回到刚才的 PowerShell,确认文件已经保存,再运行:
ls
python -X utf8 assertions_lab.py程序输出:
good: structure=通过 ownership=通过 amount=通过 effect=通过 总体=通过
wrong-owner: structure=通过 ownership=失败 amount=通过 effect=通过 总体=失败
wrong-amount: structure=通过 ownership=通过 amount=失败 effect=通过 总体=失败
missing-effect: structure=通过 ownership=通过 amount=通过 effect=失败 总体=失败
duplicate-effect: structure=通过 ownership=通过 amount=通过 effect=失败 总体=失败五行输出各自暴露哪条契约
good 的结构、归属、金额和效果都通过,因此总体通过。wrong-owner 的格式合法,确实存在一条与输出相同的账本记录,但用户为user-b,所以只有ownership失败。它说明“写进账本了”还不能说明“写对了”。
wrong-amount 已退90元,因此amount失败;记录与输出一致,effect仍通过。missing-effect 的输出看上去正确,但账本为空,effect失败。duplicate-effect 账本有两条目标单退款,仍然effect失败,防止“找到其中一条匹配记录就算成功”。
代码先判断structure,才访问可能缺失的字段。金额用 type(value) is int 检查,因为True不能作为1元。matching 先筛出目标订单的记录,其他订单不会造成重复;目标记录必须恰好一条,且回执、订单、用户、金额都相同。
总体逻辑写成:
accepted = structure AND ownership AND amount AND effect若统计这五个固定场景的总体通过率,通过数为1、分母为5,所以1 ÷ 5 = 20%。这组数据由一条正常与四条错误案例组成,分开报告检查项比单看这个总体比例更能定位问题。
补一条账本记录,看看哪个失败消失
在 scenarios() 中,把missing-effect这一行最后的空列表 [] 改成 deepcopy(LEDGER),保存并运行 python -X utf8 assertions_lab.py。这行的effect和总体会从失败变为通过,其他四行保持原结果。恢复空列表,再运行测试。
再留意wrong-owner:仅给它补更多账本记录不能修复用户归属;问题必须在产生退款之前解决。评测器用细项指出问题,被测业务执行器负责避免错误动作。评分器本身也需要测试,尤其是合法格式、错误业务、重复效果这些容易混淆的组合。
把断言写得细,但不要拘泥无关表面
任务要求整数100元,检查整数100有明确业务理由。若要求自由格式解释,就不要把一整段文案逐字相等设成通过条件;正确措辞的变化会被误伤。对于可以采用多条合法路线的任务,优先检查必要条件与结果,而不是无关的调用顺序。
Python unittest 文档可查看assertEqual、assertTrue和assertRaises的使用方式。Anthropic 的代码评分器说明比较了确定性检查与开放质量评审的适用范围,重点读code-based graders与评分器的脆弱性。
保存测试并检查关键条件
7项测试检查正确退款、格式合法但用户错误、金额错误、空账本、重复效果、字段与类型错误,以及无关订单不干扰目标订单检查。 将下方代码保存为同一文件夹的 test_assertions_lab.py,运行:
ls
python -X utf8 -m unittest -v test_assertions_lab.py看到 Ran 7 tests 与 OK 表示这些固定条件全部通过。若找不到文件,先用 dir 核对当前文件夹及两份文件名;若出现具体断言失败,先恢复正文中的代码与预置数据,再对照该项测试的条件。
完整测试:test_assertions_lab.py
"""确保格式合法不能掩盖业务错误,业务效果必须真正存在。"""
from copy import deepcopy
from pathlib import Path
import sys
import unittest
sys.path.insert(0, str(Path(__file__).parent))
import assertions_lab as lab
class AssertionTests(unittest.TestCase):
def test_good_result_passes_all_checks(self):
checks, passed = lab.grade(lab.GOOD, lab.LEDGER)
self.assertTrue(passed)
self.assertTrue(all(checks.values()))
def test_valid_structure_can_have_wrong_owner(self):
output = dict(lab.GOOD, owner="user-b")
checks, passed = lab.grade(output, [dict(lab.LEDGER[0], owner="user-b")])
self.assertTrue(checks["structure"])
self.assertFalse(checks["ownership"])
self.assertFalse(passed)
def test_wrong_amount_is_separate_failure(self):
output = dict(lab.GOOD, amount=90)
checks, passed = lab.grade(output, [dict(lab.LEDGER[0], amount=90)])
self.assertTrue(checks["ownership"])
self.assertFalse(checks["amount"])
self.assertFalse(passed)
def test_empty_ledger_cannot_prove_success(self):
checks, passed = lab.grade(lab.GOOD, [])
self.assertFalse(checks["effect"])
self.assertFalse(passed)
def test_duplicate_effect_fails(self):
checks, passed = lab.grade(lab.GOOD, lab.LEDGER + lab.LEDGER)
self.assertFalse(checks["effect"])
self.assertFalse(passed)
def test_missing_field_and_boolean_amount_fail_structure(self):
missing = deepcopy(lab.GOOD)
del missing["receipt"]
for output in (missing, dict(lab.GOOD, amount=True), "已退款"):
checks, passed = lab.grade(output, lab.LEDGER)
self.assertFalse(checks["structure"])
self.assertFalse(passed)
def test_unrelated_order_does_not_create_duplicate(self):
ledger = deepcopy(lab.LEDGER) + [dict(lab.LEDGER[0], order_id="order-2")]
self.assertTrue(lab.grade(lab.GOOD, ledger)[1])
if __name__ == "__main__":
unittest.main()课后练习展开习题收起习题
正在读取本地记录…
不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。
选择题 · 结构合法但退款金额错误,哪些检查能发现
结构合法但退款金额错误,哪些检查能发现?
对应知识点:L7-assertions
简答题 · 解释机制
一条断言失败应提供哪些信息便于定位?
对应知识点:L7-assertions
代码题 · 核对给定数据
订单金额100,结果金额1000,写出会失败的金额断言。
对应知识点:L7-assertions
场景题 · 分析具体变化
一次结果有字段、工具和金额三项错误,评测应怎样记录?
对应知识点:L7-assertions
描述会发送给本站维护者,用于修订文章,保存90天。请只填写文章问题,省略个人信息、密钥和内部资料。