You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

哪些测试输入会导致QuickCheck属性挂起?QC.within无法终止循环

问题排查:找出导致测试挂起的输入

我有一个复杂函数的测试用例,不明原因地在部分平台上出现挂起情况,希望找出导致该挂起行为的测试输入。我尝试使用QuickCheck的within函数使测试用例超时,但即使使用-O1编译,它也无法中断循环。请问还有什么方法可以让我的测试套件上报存在问题的测试输入?

简化后的测试代码 (test/Main.hs)

module Main (main) where

import Test.Tasty
import Test.Tasty.QuickCheck as QC

main :: IO ()
main = defaultMain props

props :: TestTree
props = testGroup "properties"
  [ QC.testProperty "hangy" hangy
{- Unfortunately `within` isn't able to disrupt to the hang in my actual testcase.
  , QC.testProperty "within" $ \n -> QC.within 10000 $ hangy n
-}
  ]

hangy :: Int -> Bool
hangy n | n `mod` 5 == 0 = let x = x in x
        | otherwise = True

测试依赖

build-depends:    base, tasty, tasty-quickcheck

解决方案

1. 禁用导致异常屏蔽的GHC优化

GHC在-O1/-O2优化下,会把某些无限递归(比如示例中的let x = x in x)编译成不会检查异步异常的死循环,导致QuickCheck的within无法中断。可以通过以下方式解决:

  • 给挂起的函数添加NOINLINE pragma,阻止GHC过度优化:
    {-# NOINLINE hangy #-}
    hangy :: Int -> Bool
    hangy n | n `mod` 5 == 0 = let x = x in x
            | otherwise = True
    
  • 或者在cabal文件的测试目标中添加编译选项:
    ghc-options: -fno-full-laziness -fno-state-hack
    

2. 使用Tasty的全局/单测超时机制

Tasty自带的超时机制不依赖函数内部的异常处理,直接通过进程管理终止超时测试,同时会记录触发超时的输入:

  • 给单个测试属性设置超时(单位是微秒,示例为10秒):
    props :: TestTree
    props = testGroup "properties"
      [ QC.testProperty "hangy" $ withOption (\opts -> opts { mkTimeout = Just 10000000 }) hangy
      ]
    
  • 或者在运行测试时通过命令行参数设置全局超时:
    cabal test --test-option="--timeout 10s"
    

3. 手动记录测试输入

修改测试逻辑,在执行测试前先打印输入,挂起时最后输出的输入就是问题输入:

hangyTest :: Int -> IO Bool
hangyTest n = do
  putStrLn $ "Testing input: " ++ show n
  return $ hangy n

props :: TestTree
props = testGroup "properties"
  [ QC.testProperty "hangy" $ QC.ioProperty . hangyTest
  ]

4. 切换到QuickCheck原生测试Runner

使用QuickCheck的原生runner,它的超时处理对某些优化场景更有效:

main :: IO ()
main = verboseCheck hangy

运行时添加超时参数:

cabal test --test-option="--timeout 10s"

内容的提问来源于stack exchange,提问作者sjakobi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 07:53:16