简体   繁体   English

Haskell Tasty.HUnit:如何使用 IO 运行多个测试

[英]Haskell Tasty.HUnit : how to run multiple tests with IO

I'm trying to run multiple tests (that is, multiple Assertions) within a Test.Tasty testGroup;我正在尝试在 Test.Tasty testGroup 中运行多个测试(即多个断言); but feeding in a single "object" that has been read in from IO.但是输入从 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;但是,以上要求在调用测试之前执行 IO; and is performed even if only a subset of tests is requested (whether or not that subset actually uses the IO result).并且即使仅请求测试的子集(无论该子集是否实际使用 IO 结果)也会执行。

Alternatively, each testCase can perform its own IO (an Assertion is just IO (), after all);或者,每个 testCase 都可以执行自己的 IO(毕竟 Assertion 就是 IO()); but that potentially means IO being performed repeatedly, which is not what I want.但这可能意味着重复执行 IO,这不是我想要的。

Alternatively again, a testCase can include a do {} block which calls multiple assertions;或者,一个 testCase 可以包含一个调用多个断言的do {}块; 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; Test.Tasty.withResource看起来很有希望; and if its third argument were a -> TestTree , I could work with that;如果它的第三个参数是a -> TestTree ,我可以使用它; 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.然而,它不是,它是IO a -> TestTree ,我正在努力研究如何安全地提取a以在我的测试用例中使用。

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: 因为type Assertion = IO () ,这两个部分应该足够了:

(>>=) :: 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. 即它看起来你多次读取文件,但tasty只执行一次动作。 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). 这就是评论所说的:)尝试将putStrLn "trace debug"添加到acquire以确定它大部分运行一次(即如果你只是要求no io测试则不运行)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM