Я хочу пройти 99 Haskell Problems, и я хочу сосредоточиться на решении, но с тестированием. Если у меня есть решение первой проблемы в виде 3-строчного файла .hs
,
myLast :: [a] -> a
myLast [x] = x
myLast (_:xs) = myLast xs
Каков минимальный объем кода, который я могу добавить к этому, чтобы я мог добавлять тесты inline и запускать их с помощью runhaskell
?
Ответ 1
QuickCheck (который в основном генерирует тестовые входы для вас), вероятно, лучший способ проверить чистую функцию. И если соответствующая функция имеет аналог стандартной библиотеки, вы можете просто проверить свою функцию, используя стандартную модель:
{-# LANGUAGE TemplateHaskell #-}
import Test.QuickCheck
import Test.QuickCheck.All
myLast :: [a] -> a
myLast [x] = x
myLast (_:xs) = myLast xs
-- here we specify that 'myLast' should return exactly the same result
-- as 'last' for any given 'xs'
prop_myLast xs = myLast xs == last xs
return [] -- need this for GHC 7.8
-- quickCheckAll generates test cases for all 'prop_*' properties
main = $(quickCheckAll)
Если вы запустите его, вы получите:
=== prop_myLast on tmp3.hs:12 ===
*** Failed! Exception: 'tmp3.hs:(7,1)-(8,25): Non-exhaustive patterns in function myLast' (after 1 test):
[]
False
потому что ваш myLast
не обрабатывает случай []
(он должен, но должен, вероятно, генерировать ошибку, такую как "последний" ).
Но здесь мы можем просто отрегулировать наш тест, но указав, что должны использоваться только непустые строки (используя ==>
combinator):
prop_myLast xs = length xs > 0 ==> myLast xs == last xs
Что делает все 100 автоматически сгенерированных тестовых случаев для myLast
:
=== prop_myLast on tmp3.hs:11 ===
+++ OK, passed 100 tests.
True
PS Другим способом указания поведения myLast
может быть:
prop_myLast2 x xs = myLast (xs++[x]) == x
Или лучше:
prop_myLast3 x xs = x `notElem` xs ==> myLast (xs++[x]) == x
Ответ 2
hspec также является платформой тестирования для Haskell, которая вдохновлена Ruby RSpec. Он интегрируется с QuickCheck, SmallCheck и HUnit.