尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

掌握Hammox.protect:真实实现函数契约保护的4种写法,一个都不能漏

掌握Hammox.protect:真实实现函数契约保护的4种写法,一个都不能漏 掌握Hammox.protect真实实现函数契约保护的4种写法一个都不能漏【免费下载链接】hammox automated contract testing via type checking for Elixir functions and mocks项目地址: https://gitcode.com/gh_mirrors/ha/hammoxHammox 是 Elixir 生态中做契约测试contract testing的轻量库而Hammox.protect是它最核心的能力让真实的业务实现在运行时接受 behaviour typespec 的类型检查参数传错或返回值不合约定立即抛出Hammox.TypeMatchError。这篇文章带你一次吃透Hammox.protect的 4 种写法从单个函数到批量保护、再到一行宏魔法照着选就不会错 为什么需要 Hammox.protect测试通过了上线却崩了先理解它解决的问题。假设Database行为约定get_users/0返回{:ok, [binary()]}早期 mock 返回[joe, jim]测试一路绿灯后来行为签名改成了返回 ok/error 元组旧 mock 没有同步修改——测试依然通过真实数据库一接上就炸这就是契约违约mock 与 behaviour 不再一致。Hammox 会自动拦截这类问题而对真实实现real implementation的检查就靠Hammox.protect完成。它返回一个包装后的匿名函数调用时校验参数类型和返回类型不合约定立即报错并附带清晰的类型不匹配信息核心校验逻辑见 lib/hammox.ex。写法一MFA 元组保护单个函数Hammox.protect/2最精确的方式——只保护一个函数。传入{模块, 函数名, 元数}元组和 behaviour 模块get_users_0 Hammox.protect({RealDatabase, :get_users, 0}, Database) # 调用时自动校验参数与返回值 assert {:ok, [real-jim, real-joe]} get_users_0.()适合只关心一两个关键函数的场景。函数必须真实存在否则直接抛ArgumentError参见 lib/hammox.ex 中的存在性检查。写法二模块 behaviour 批量保护Hammox.protect/2实际项目更常用这种。传入实现模块和 behaviour 模块一次性保护所有回调函数返回一个以函数名_元数为 key 的 map%{get_users_0: get_users_0, get_user_1: get_user_1} Hammox.protect(RealDatabase, Database)官方推荐把它放进setup_all钩子通过测试上下文分发避免每个用例重复生成setup_all do Hammox.protect(RealDatabase, Database) end test get_users/0 返回值符合契约, %{get_users_0: get_users_0} do assert {:ok, [a, b]} get_users_0.() end如果一个模块实现了多个 behaviour直接传列表即可map 会自动合并多 behaviour 用法示例见 lib/hammox.ex。写法三批量保护 精确挑选函数Hammox.protect/3批量保护默认覆盖全部回调但有时只需要盯住几个核心函数第三个参数可以显式指定%{add_2: add_2, multiply_2: multiply_2} Hammox.protect(TestCalculator, Calculator, add: 2, multiply: 2)支持同一函数的多个元数add: [2, 3]。这样生成的 map 更聚焦setup_all上下文也更干净。写法四一行宏魔法use Hammox.Protect不想写 setup、不想管 map就在测试模块顶部加一行。它会在编译期把目标模块的受保护函数像 import 一样定义进当前模块宏实现见 lib/hammox/protect.exdefmodule RealDatabaseTest do use ExUnit.Case, async: true use Hammox.Protect, module: RealDatabase, behaviour: Database test get_users/0 返回用户列表 do assert {:ok, [joe, jim]} get_users() end end三个可选参数选项说明:module必填要保护的实现模块:behaviour用于校验的 behaviour可省略默认与:module相同:funs只保护指定函数作用域仅限它前面那个:behaviour一个模块实现多个 behaviour 时可以写多组behaviour/funsuse Hammox.Protect, module: MultiBehaviourImplementation, behaviour: SmallBehaviour, funs: [foo: 0, other_foo: 1], # 只影响 SmallBehaviour behaviour: AdditionalBehaviour # 未指定 funs全部回调都受保护⚠️ 两个常见报错忘写:module会抛ArgumentError目标模块没有任何回调如普通实现模块、空 behaviour也会直接报错提示错误处理逻辑见 lib/hammox/protect.ex。完整的错误场景用例可以参考 test/hammox/protect_test.exs以及测试支撑模块 test/support/protect/behaviour.ex。顺手技巧behaviour 和实现在同一模块很多项目习惯把callback声明和函数实现写在同一个模块里。此时 Hammox 提供行为-实现一体的捷径只传一个模块即可# 以下两行等价 Hammox.protect({Calculator, :add, 2}) Hammox.protect({Calculator, :add, 2}, Calculator) # 批量模式同理 Hammox.protect(Calculator) # 等价于 Hammox.protect(Calculator, Calculator)4 种写法怎么选一张速查表场景推荐写法只测一两个关键函数写法一MFA 元组整个模块纳入契约测试最常用写法二setup_all 模块批量批量中只想覆盖部分函数写法三指定funs列表追求极简、接受宏魔法写法四use Hammox.Protect已知限制写测试前先知道typespec 中的匿名函数类型只检查元数不检查其参数和返回类型单个函数最多支持 253 个参数BEAM 上限 255包装函数占用了 2 个见 lib/hammox.ex需要被保护函数所在 behaviour 有 typespec缺失时会抛TypespecNotFoundError总结Hammox.protect把类型检查变成了运行时测试写法一管精确、写法二管批量、写法三管取舍、写法四管省事。配合 Hammox 自动检查的 mock 契约lib/hammox.ex你的 behaviour、mock、真实实现三者就形成了一个铁三角任何一边的契约违约都会在测试阶段暴露。想进一步了解它的 Telemetry 事件可以看项目内的 guides/Telemetry.md。【免费下载链接】hammox automated contract testing via type checking for Elixir functions and mocks项目地址: https://gitcode.com/gh_mirrors/ha/hammox创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表