I have found other questions on similar lines but nothing that answers my question in this particular scenario. Furthermore, there seem to be few resources which succinctly cover the subject of unit testing IO actions in Haskell.
Let's say I have this typeclass for my database communication:
data Something = Something String deriving Show
class MonadIO m => MonadDB m where
getSomething :: String -> m Something
getSomething s = do
... -- assume a DB call is made and an otherwise valid function
instance MonadDB IO
Run Code Online (Sandbox Code Playgroud)
and this function which uses it:
getIt :: MonadDB m => m (Int, Something)
getIt = do
s@(Something str) <- getSomething "hi"
return (length str, s) -- excuse the contrived example
Run Code Online (Sandbox Code Playgroud)
I wish to test this getIt function with hspec but without it talking to the database, which presumably means replacing which MonadDB it uses, but how do I achieve that?
这对您有用吗?
#!/usr/bin/env stack
-- stack exec --package transformers --package hspec -- ghci
import Control.Monad.IO.Class
import Control.Monad.Trans.Identity
import Data.Char
import Test.Hspec
data Something = Something String deriving (Eq, Show)
class MonadIO m => MonadDB m where
getSomething :: String -> m Something
getSomething s = return $ Something (map toUpper s)
instance MonadDB IO
instance MonadIO m => MonadDB (IdentityT m)
getIt :: MonadDB m => m (Int, Something)
getIt = do
s@(Something str) <- getSomething "hi"
return (length str, s)
main :: IO ()
main = hspec $ do
describe "Some tests" $ do
it "test getIt" $ do
runIdentityT getIt `shouldReturn` (2, Something "HI")
it "test getIt should fail" $ do
runIdentityT getIt `shouldReturn` (1, Something "HI")
Run Code Online (Sandbox Code Playgroud)
您也许还可以使用ReaderT或StateT“提供”数据或转换getSomething以供在测试查询时使用。
编辑:在hspec中使用示例。