web-dev-qa-db-fra.com

Tests unitaires haskell simples

Je veux passer en revue 99 Problèmes Haskell , et je veux me concentrer sur la solution, mais avec des tests. Si j'ai la solution au premier problème sous forme de fichier .hs de 3 lignes,

myLast :: [a] -> a
myLast [x] = x
myLast (_:xs) = myLast xs

Quelle est la quantité minimale de code que je peux ajouter pour pouvoir ajouter des tests en ligne et les exécuter avec runhaskell?

49
Daniel Huckstep

QuickCheck (qui génère essentiellement des entrées de test pour vous) est probablement le meilleur moyen de tester une fonction pure. Et si une fonction en question a un analogue de la bibliothèque standard, vous pouvez simplement tester votre fonction en utilisant le modèle standard comme modèle:

{-# 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)

Si vous l'exécutez, vous obtiendrez:

=== prop_myLast on tmp3.hs:12 ===
*** Failed! Exception: 'tmp3.hs:(7,1)-(8,25): Non-exhaustive patterns in function myLast' (after 1 test):  
[]
False

parce que votre myLast ne gère pas le cas [] (il devrait mais devrait probablement renvoyer une erreur du type 'last'). Mais ici, nous pouvons simplement ajuster notre test en spécifiant que seules les chaînes non vides doivent être utilisées ==> combinator):

prop_myLast xs = length xs > 0 ==> myLast xs == last xs

Ce qui fait que tous les 100 cas de test générés automatiquement passent avec myLast:

=== prop_myLast on tmp3.hs:11 ===
+++ OK, passed 100 tests.
True

PS Une autre façon de spécifier un comportement myLast peut être:

prop_myLast2 x xs = myLast (xs++[x]) == x

Ou mieux:

prop_myLast3 x xs = x `notElem` xs ==> myLast (xs++[x]) == x
64
Ed'ka

hspec est également un framework de test pour Haskell, inspiré de Ruby RSpec. Il s'intègre à QuickCheck, SmallCheck et HUnit. 

0
stian