I'm trying to run multiple tests (that is, multiple Assertions) within a Test.Tasty testGroup; but feeding in a single "object" that has been read in from IO.
For example, I read & parse a file; and I want to make multiple assertions against the result of that file. Something like
tests :: [String] -> TestTree
tests ls = testGroup "tests" [ testCase "length" $ length ls @?= 2
, testCase "foo" $ ls !! 0 @?= "foo"
]
main = do
ls :: [String] <- read <$> readFile "/tmp/hunit"
defaultMain (tests ls)
However, the above requires that the IO is performed before calling the tests; and is performed even if only a subset of tests is requested (whether or not that subset actually uses the IO result).
Alternatively, each testCase can perform its own IO (an Assertion is just IO (), after all); but that potentially means IO being performed repeatedly, which is not what I want.
Alternatively again, a testCase can include a do {}
block which calls multiple assertions; but this will mean that individual tests are not selectable, and won't get verbose output to confirm which tests were run.
Test.Tasty.withResource
looks hopeful; and if its third argument were a -> TestTree
, I could work with that; however, it isn't, it's IO a -> TestTree
, and I'm struggling to work out how to safely extract the a
to use in my test cases.
I've tried playing with this, but I fear I'm missing something fundamental...
Any help gratefully received.
Seems like it should be pretty simple; since type Assertion = IO ()
, these two pieces should be enough:
(>>=) :: IO a -> (a -> Assertion) -> Assertion
testCase :: TestName -> Assertion -> TestTree
You are right looking at the
withResource
:: IO a -- ^ initialize the resource
-> (a -> IO ()) -- ^ free the resource
-> (IO a -> TestTree)
-- ^ @'IO' a@ is an action which returns the acquired resource.
-- Despite it being an 'IO' action, the resource it returns will be
-- acquired only once and shared across all the tests in the tree.
-> TestTree
The idea is that you can write your scenario as:
tests :: IO String -> TestTree
tests lsIO = testGroup "tests"
[ testCase "length" $ do
ls <- lsIO
length ls @?= 2
, testCase "foo" $ do
ls <- lsIO
ls !! 0 @?= "foo"
, testCase "no io" $ do
return ()
]
main :: IO ()
main = defaultMain (withResource acquire tests)
acquire :: IO [String]
acquire = read <$> readFile "/tmp/hunit"
ie it looks like you'd read file multiple times, but tasty
performs the action only once. That's what the comment says :) Try adding putStrLn "trace debug"
to the acquire
to see for sure, that it's run mostly once (ie not run if you only ask for no io
test).
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.