Cabal执行cabal test提示测试通过但实际测试失败原因排查
为什么Cabal显示测试通过但日志中存在明确的测试失败信息?
Cabal判断测试套件是否通过,根本不会解析日志文件内容,只认测试可执行文件运行结束后的进程退出码:退出码为0就标记为PASS,非0才判定为FAIL。你碰到的情况本质是测试执行遇到失败后,没有返回正确的非0退出码,才被Cabal误判为通过。
常见的触发原因有三类:
- 直接调用了不会主动设置退出码的测试接口
最典型的就是裸用QuickCheck的quickCheck函数跑属性测试:这个函数只会把失败信息打印到输出流,既不会主动终止程序,也不会修改进程退出码,哪怕所有用例都失败,程序跑完还是默认返回0。比如下面的错误写法就会触发这个问题:main = quickCheck myFailingProp - 测试入口封装逻辑吞掉了失败状态
如果用tasty、test-framework这类测试聚合框架,没直接用框架提供的defaultMain当程序入口,而是自己额外包了一层执行逻辑、捕获了异常但没在测试失败时主动触发退出失败,就会导致退出码始终为0。 - 全局异常处理误拦了失败信号
如果测试代码里写了全局异常捕获逻辑,把测试框架抛出的失败异常也拦住了,最后走到正常退出分支,同样会让Cabal误判。
对应的修复方法很简单:
- 裸用QuickCheck的场景:把
quickCheck换成quickCheckResult拿到测试结果,根据结果主动设置退出码,参考写法:import System.Exit (exitSuccess, exitFailure) import Test.QuickCheck (quickCheckResult, isSuccess) main = do testRes <- quickCheckResult myProp if isSuccess testRes then exitSuccess else exitFailure - 使用测试框架的场景:直接用框架自带的
defaultMain作为测试程序的main入口,不要自己额外封装吞掉退出逻辑,框架会自动在测试失败时返回正确的非0退出码。
你可以自己验证下问题根因:单独运行Cabal编译出的测试可执行文件(路径一般在dist/build/<测试套件名>/<测试套件名>下),跑完立刻在shell执行echo $?(Linux/macOS)或echo %errorlevel%(Windows)看退出码,如果明明有失败用例但退出码是0,就完全符合上述问题场景。
内容的提问来源于stack exchange,提问作者Hongtao Yang
相关产品推荐
相关产品推荐

