Custom options in Tasty
Published on
Tasty 0.6 is released, making it possible to create custom options just for your test suite!
Add your own option in three easy steps:
- Define a datatype to represent the option, and make it an instance
of
IsOption
- Register the options with the
includingOptions
ingredient - To query the option value, use
askOption
.
Examples follow.
Ignoring a test
My use case is a test suite that has a number of tests that fail on a certain build bot. I can’t fix the build bot configuration ATM, so I’d like to be able to mark these tests as known-fail in the build script for this particular build bot. — 23Skidoo
To some extent this is just a way around Tasty’s limited pattern language (which will improve, too!), but I still find it pretty nice.
With the following code, you can disable the second test by passing a
--buildbot
command-line option.
{-# LANGUAGE DeriveDataTypeable #-}
import Test.Tasty
import Test.Tasty.Options
import Test.Tasty.HUnit
import Data.Typeable (Typeable)
import Data.Tagged
import Data.Proxy
import Options.Applicative
newtype BuildBot = BuildBot Bool
deriving (Eq, Ord, Typeable)
instance IsOption BuildBot where
= BuildBot False
defaultValue = fmap BuildBot . safeRead
parseValue = return "buildbot"
optionName = return "Running under a build bot"
optionHelp =
optionCLParser fmap BuildBot $
switchoptionName :: Tagged BuildBot String))
( long (untag (<> help (untag (optionHelp :: Tagged BuildBot String))
)
= defaultMainWithIngredients ings $
main $ \(BuildBot bb) ->
askOption "Tests" $
testGroup "Successful test" $ return () ] ++
[ testCase if bb
then []
else [ testCase "Failing test" $ assertFailure "build bot" ]
where
=
ings Option (Proxy :: Proxy BuildBot)] :
includingOptions [ defaultIngredients
Controlling the depth
When running the tests is there any general solution to set the
Depth
parameter for the (individual) tests, or better yet, a fine grained solution to set theDepth
parameter for individual fields? — jules
Not that I recommend doing this — see this answer.
But here’s how you can do it if you’re sure you want it.
(This was also possible to hack with earlier versions of Tasty — see this gist).
{-# LANGUAGE DeriveDataTypeable #-}
import Test.Tasty
import Test.Tasty.Options
import Test.Tasty.SmallCheck
import Test.SmallCheck.Series
import Control.Applicative
import Data.Proxy
import Data.Typeable
data T1 = T1 { p1 :: Int,
p2 :: Char,
p3 :: Int
deriving (Eq, Show)
}
newtype P1Depth = P1Depth { getP1Depth :: Int }
deriving Typeable
instance IsOption P1Depth where
= P1Depth 5
defaultValue = fmap P1Depth . safeRead
parseValue = return "smallcheck-depth-p1"
optionName = return "Depth to use for p1"
optionHelp
t1Series :: Monad m
=> Int -- depth of p1
-> Series m T1
= decDepth $
t1Series d T1 <$> localDepth (const d) series <~> series <~> series
main :: IO ()
= defaultMainWithIngredients (optsIng : defaultIngredients) $
main $ \(P1Depth p1d) ->
askOption "Test1" $
testProperty $
over (t1Series p1d) -> x == x
\x where
= includingOptions [Option (Proxy :: Proxy P1Depth)] optsIng
To increase the depth of p1
to 20, pass
--smallcheck-depth-p1 20
on the command line.