如何对调用硬编码内部函数的Plutus合约HTTP接口编写测试用例
解决方案
方案1:条件编译注入测试控制逻辑(生产零侵入)
这是最适配你场景的方案,完全不需要修改f1的原有逻辑和入参,生产环境构建时不会残留任何测试相关代码:
- 给代码添加CPP预编译支持,拆分
f2的实现为生产分支和测试分支:
{-# LANGUAGE CPP #-} data ActualData = ActualData String String Integer newtype Input = Input [ActualData] #ifdef TEST_BUILD import Data.IORef import System.IO.Unsafe -- 仅测试环境存在的全局变量,存储自定义测试输入 {-# NOINLINE testInputRef #-} testInputRef :: IORef Input testInputRef = unsafePerformIO $ newIORef defaultInput -- 仅测试环境暴露的HTTP配置接口 setTestInput :: Contract () Schema Text () setTestInput = do customInput <- endpoint @"set-test-input" liftIO $ writeIORef testInputRef customInput f2 :: Input f2 = unsafePerformIO $ readIORef testInputRef #else -- 生产环境完全保留原有逻辑 f2 :: Input f2 = defaultInput #endif -- 原有默认输入抽为公共常量 defaultInput :: Input defaultInput = Input [ ActualData "BlackRock" "pkh1" 10 , ActualData "GreenRock" "pkh2" 20 ] f1:: Contract () Schema Text () f1 = do let input = f2 -- 原有逻辑保持不变 ...
- 测试流程:
- 测试环境构建时添加
-DTEST_BUILD编译参数,此时服务会额外暴露setTestInput的HTTP端点 - 执行每个测试用例前,先调用
setTestInput接口传入你需要的自定义输入 - 再调用
f1的HTTP接口,此时f1读取到的f2返回值就是你指定的测试输入 - 生产环境构建时不添加
TEST_BUILD宏,所有测试相关代码会被完全剔除,不需要做额外的JSON序列化适配,和原有生产代码完全一致
方案2:测试时重载f2实现(无需修改业务代码)
如果不想引入条件编译,可以在测试项目中重载f2的实现:
- 测试模块导入业务模块时隐藏原有f2:
import 业务模块名 hiding (f2) - 在测试模块内自定义f2的实现,返回对应测试用例需要的输入值
- 测试构建的服务会使用重载后的f2实现,业务代码完全不需要改动
内容的提问来源于stack exchange,提问作者thirsty
相关产品推荐
相关产品推荐

