Тест QuickCheck случайно зависает
Я новичок в Хаскеле. Я играю с тестами QuickCheck, пытаюсь протестировать простую функцию calculateStrengthSingle
(см. источник тестируемого ниже)
# Fighter.hs
module Fighter
( Quantity(Quantity)
, Fighter(TeamPlayer, LoneWolf, Polymorph)
, Strength(Strength)
, calculateStrengthSingle)
where
import System.Random
data Strength = Strength Double
instance Eq Strength where
Strength s1 == Strength s2 =
s1 == s2
instance Ord Strength where
Strength s1 < Strength s2 =
s1 < s2
data Quantity = Quantity Int deriving (Show)
instance Random Quantity where
randomR (Quantity lo, Quantity hi) g =
let rand = randomR (lo, hi) g
(r, g1) = rand
in (Quantity r, g1)
random g =
let rand = random g
(r, g1) = rand
in (Quantity r, g1)
data Fighter = TeamPlayer
| LoneWolf
| Polymorph
deriving (Show)
calculateStrengthSingle :: Quantity -> Fighter -> Strength
calculateStrengthSingle (Quantity number) TeamPlayer =
Strength(log (fromIntegral number))
calculateStrengthSingle _ _ = Strength 0.0
Тест выглядит так
# TestFighter.hs
import qualified Test.QuickCheck as QuickCheck
import Fighter
prop_StrengthPositive quantity fighter =
Fighter.calculateStrengthSingle quantity fighter >= Strength 0.0
instance QuickCheck.Arbitrary Fighter.Fighter where
arbitrary = QuickCheck.oneof([return Fighter.TeamPlayer, return Fighter.LoneWolf, return Fighter.Polymorph])
instance QuickCheck.Arbitrary Fighter.Quantity where
arbitrary = QuickCheck.choose(Fighter.Quantity 1, Fighter.Quantity 10)
main :: IO()
main = do
QuickCheck.quickCheck prop_StrengthPositive
Когда я делаю runhaskell TestFighter.hs
есть выход (1 test)
(номер меняется, иногда это 0
в других случаях это 4
) и процессор загружен на 100%. Ничего не происходит в течение минуты или около того. Когда я прерываю программу Ctrl+C
выплевывает что-то вроде
^C*** Failed! Exception: 'user interrupt' (after 1 test):
Quantity 2
TeamPlayer
Вопросы:
- Где я все испортил?
- Как я могу отлаживать случаи бесконечного вычисления, как этот?
2 ответа
Вы не определили Ord
экземпляр для Strength
правильно. Вам нужно определить <=
и не <
,
Только с <
определил функцию <=
входит в бесконечный цикл, как это определено с точки зрения compare
а также compare
определяется с точки зрения <=
, Минимальное определение должно определять либо compare
или же <=
,
Вот фиксированный код для Ord
пример
instance Ord Strength where
Strength s1 <= Strength s2 =
s1 <= s2
Вы можете попробовать запустить тест с -o 1
в качестве параметра, который вызывает тайм-аут после одной секунды. Затем он может отобразить ввод, который вызвал зависание вашей программы. Это не говорит вам точно, где проблема, но это хорошее начало.
РЕДАКТИРОВАТЬ: так я использую тестовый фреймворк с Cabal
test-Suite runTests
hs-source-dirs: src, test
type: exitcode-stdio-1.0
main-is: RunTests.hs
other-modules:
<...>
build-depends: base >= 3 && < 5,
HUnit,
test-framework,
test-framework-th,
test-framework-hunit,
test-framework-quickcheck2,
QuickCheck,
Чтобы быть полным в моем описании, я строю, используя:
cabal-dev install --enable-tests