Auto discovery for Tasty with support for ingredients and test tree generation.
tasty-auto: Simple auto discovery for Tasty
This package provides auto discovery for the tasty test framework.
Install tasty-auto (using cabal or stack)
Create a file test/test.hs
-- test/test.hs
{-# OPTIONS_GHC -F -pgmF tasty-auto #-}
Put your tests in files with the suffix
*Test.hs
or*Spec.hs
. Functions with the following prefixes are automatically discovered:prop_
for QuickCheck propertiesscprop_
for SmallCheck propertiescase_
for HUnit test cases (overloaded forIO ()
,IO String
and(String -> IO ()) -> IO
)spec_
for Hspec specificationstest_
for Tasty TestTrees (overloaded forTestTree
,[TestTree]
,IO TestTree
andIO [TestTree]
)
Examples
QuickCheck
-- test/PropTest.hs
module PropTest where
prop_Addition_is_commutative :: Int -> Int -> Bool
prop_Addition_is_commutative a b = a + b == b + a
HUnit
-- test/CaseTest.hs
module CaseTest where
import Test.Tasty.HUnit
case_List_comparison_with_different_length :: IO ()
case_List_comparison_with_different_length = [1, 2, 3] `compare` [1,2] @?= GT
Hspec
-- test/TestSpec.hs
module TestSpec where
import Test.Tasty.Hspec
spec_Prelude :: Spec
spec_Prelude = do
describe "Prelude.head" $ do
it "returns the first element of a list" $ do
head [23 ..] `shouldBe` (23 :: Int)
Test trees
-- test/TreeTest.hs
{-# LANGUAGE ScopedTypeVariables #-}
module TreeTest where
import Test.Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
test_Addition :: TestTree
test_Addition = testProperty "Addition commutes" $ \(a :: Int) (b :: Int) -> a + b == b + a
test_Multiplication :: [TestTree]
test_Multiplication =
[ testProperty "Multiplication commutes" $ \(a :: Int) (b :: Int) -> a * b == b * a
, testProperty "One is identity" $ \(a :: Int) -> a * 1 == a
]
test_Generate_Tree :: IO TestTree
test_Generate_Tree = do
input <- pure "Some input"
pure $ testCase input $ pure ()
test_Generate_Trees :: IO [TestTree]
test_Generate_Trees = do
inputs <- pure ["First input", "Second input"]
pure $ map (\s -> testCase s $ pure ()) inputs
Configuration options
You can add tasty ingredients with the -optF
option:
-- test/test.hs
{-# OPTIONS_GHC -F -pgmF tasty-auto -optF --ingredient=Test.Tasty.Runners.Html.htmlRunner -optF --ingredient=Test.Tasty.Runners.AntXML.antXMLRunner #-}
It is possible to configure the name of the generated module, if you want to import the module somewhere.
-- test/AutoTests.hs
{-# OPTIONS_GHC -F -pgmF tasty-auto -optF --module=AutoTests #-}
Generated code
The generated code of the preprocessor looks like this:
{-# LINE 1 "test/test.hs" #-}
{-# LANGUAGE FlexibleInstances #-}
module Main (main, ingredients, tests) where
import Prelude
import qualified Test.Tasty as T
import qualified Test.Tasty.Ingredients as T
import qualified Test.Tasty.HUnit as HU
import qualified Test.Tasty.QuickCheck as QC
import qualified Test.Tasty.SmallCheck as SC
import qualified Test.Tasty.Hspec as HS
import qualified CaseTest
import qualified SCPropTest
import qualified TreeTest
import qualified PropTest
import qualified TestSpec
import qualified SubMod.PropTest
class TestCase a where testCase :: String -> a -> IO T.TestTree
instance TestCase (IO ()) where testCase n = pure . HU.testCase n
instance TestCase (IO String) where testCase n = pure . HU.testCaseInfo n
instance TestCase ((String -> IO ()) -> IO ()) where testCase n = pure . HU.testCaseSteps n
class TestGroup a where testGroup :: String -> a -> IO T.TestTree
instance TestGroup T.TestTree where testGroup _ a = pure a
instance TestGroup [T.TestTree] where testGroup n a = pure $ T.testGroup n a
instance TestGroup (IO T.TestTree) where testGroup _ a = a
instance TestGroup (IO [T.TestTree]) where testGroup n a = T.testGroup n <$> a
tests :: IO T.TestTree
tests = do
t0 <- testCase "List comparison with different length" CaseTest.case_List_comparison_with_different_length
t1 <- pure $ SC.testProperty "sort reverse" SCPropTest.scprop_sort_reverse
t2 <- testGroup "Addition" TreeTest.test_Addition
t3 <- testGroup "Multiplication" TreeTest.test_Multiplication
t4 <- testGroup "Generate Tree" TreeTest.test_Generate_Tree
t5 <- testGroup "Generate Trees" TreeTest.test_Generate_Trees
t6 <- pure $ QC.testProperty "Addition is commutative" PropTest.prop_Addition_is_commutative
t7 <- HS.testSpec "Prelude" TestSpec.spec_Prelude
t8 <- pure $ QC.testProperty "Addition is associative" SubMod.PropTest.prop_Addition_is_associative
pure $ T.testGroup "test/test.hs" [t0,t1,t2,t3,t4,t5,t6,t7,t8]
ingredients :: [T.Ingredient]
ingredients = T.defaultIngredients
main :: IO ()
main = tests >>= T.defaultMainWithIngredients ingredients