Testing functions in Haskell that do IO

后端 未结 5 2122
心在旅途
心在旅途 2020-12-23 17:06

Working through Real World Haskell right now. Here\'s a solution to a very early exercise in the book:

-- | 4) Counts the number of characters in a file
numC         


        
5条回答
  •  爱一瞬间的悲伤
    2020-12-23 17:21

    Based on my layman's understanding of Haskell, I've come to the following conclusions:

    1. If a function makes use of the IO monad, mock testing is going to be impossible. Avoid hard-coding the IO monad in your function.

    2. Make a helper version of your function that takes in other functions that may do IO. The result will look like this:

    numCharactersInFile' :: Monad m => (FilePath -> m String) -> FilePath -> m Int
    numCharactersInFile' f filePath = do
        contents <- f filePath
        return (length contents)
    

    numCharactersInFile' is now testable with mocks!

    mockFileSystem :: FilePath -> Identity String
    mockFileSystem "fileName" = return "mock file contents"
    

    Now you can verify that numCharactersInFile' returns the the expected results w/o IO:

    18 == (runIdentity .  numCharactersInFile' mockFileSystem $ "fileName")
    

    Finally, export a version of your original function signature for use with IO

    numCharactersInFile :: IO Int
    numCharactersInFile = NumCharactersInFile' readFile
    

    So, at the end of the day, numCharactersInFile' is testable with mocks. numCharactersInFile is just a variation of numCharactersInFile'.

提交回复
热议问题