使用 Hakyll 的 MonadMetadata 进行测试
Testing with Hakyll's MonadMetadata
对于我们的 Hakyll 代码库,我编写了一些辅助方法并开始围绕较新的方法添加一些 HSpec 单元测试,例如:
-- | Reject an item unless @fieldName@ is set to "true"
unlessEnabled :: MonadMetadata m
=> String
-> Item a
-> m Bool
unlessEnabled fieldName item = do
maybeValue <- getMetadataBool (itemIdentifier item) fieldName
return $ maybe True not maybeValue
-- | Try to look up a boolean field ("true" maps to @Just True@)
getMetadataBool :: MonadMetadata m
=> Identifier
-> String
-> m (Maybe Bool)
getMetadataBool ident name = do
maybeString <- getMetadataField ident name
return $ ((== "true") . map toLower) <$> maybeString
现在创建用于测试的 Item
或 Identifier
很容易,但是当 运行 一个 Hspec 时,我不确定 MonadMetadata
去哪里。
我看过 testCompiler
which feels like it might be copyable / useful (Compiler
has a MonadMetadata
instance),但我的 Haskell 深度不够...
最终(感谢@Bergi 的建议)我得到了一些工作,然后整理:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
type KeyedValuesOf a = [(String, a)]
-- | Create Metadata from basic list of key-values -- stolen from Hakyll itself.
meta :: Yaml.ToJSON a => KeyedValuesOf a -> Metadata
meta pairs = HMS.fromList [(T.pack k, Yaml.toJSON v) | (k, v) <- pairs]
-- | A 'Reader' class of our own, with a specialised environment
-- for key-value metadata pairs.
newtype MonadMetadataReader a =
MonadMetadataReader {runMonadMetadataReader :: KeyedValuesOf String -> a}
deriving (Functor, Applicative, Monad)
-- | Simple 'Metadata' holder.
-- There are never any matches found,
-- and all metadata (for all items)
-- comes from from the Reader-like environment at setup.
instance MonadMetadata MonadMetadataReader where
getMetadata identifier = MonadMetadataReader meta
getMatches pattern = return []
允许简单的单元测试,例如:
it "enables for a value of \"false\"" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) [("key", "false")]
enabled `shouldBe` True
it "disables for a value of \"true\"" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) [("key", "true")]
enabled `shouldBe` False
it "enables if no metadata found" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) []
enabled `shouldBe` True
对于我们的 Hakyll 代码库,我编写了一些辅助方法并开始围绕较新的方法添加一些 HSpec 单元测试,例如:
-- | Reject an item unless @fieldName@ is set to "true"
unlessEnabled :: MonadMetadata m
=> String
-> Item a
-> m Bool
unlessEnabled fieldName item = do
maybeValue <- getMetadataBool (itemIdentifier item) fieldName
return $ maybe True not maybeValue
-- | Try to look up a boolean field ("true" maps to @Just True@)
getMetadataBool :: MonadMetadata m
=> Identifier
-> String
-> m (Maybe Bool)
getMetadataBool ident name = do
maybeString <- getMetadataField ident name
return $ ((== "true") . map toLower) <$> maybeString
现在创建用于测试的 Item
或 Identifier
很容易,但是当 运行 一个 Hspec 时,我不确定 MonadMetadata
去哪里。
我看过 testCompiler
which feels like it might be copyable / useful (Compiler
has a MonadMetadata
instance),但我的 Haskell 深度不够...
最终(感谢@Bergi 的建议)我得到了一些工作,然后整理:
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
type KeyedValuesOf a = [(String, a)]
-- | Create Metadata from basic list of key-values -- stolen from Hakyll itself.
meta :: Yaml.ToJSON a => KeyedValuesOf a -> Metadata
meta pairs = HMS.fromList [(T.pack k, Yaml.toJSON v) | (k, v) <- pairs]
-- | A 'Reader' class of our own, with a specialised environment
-- for key-value metadata pairs.
newtype MonadMetadataReader a =
MonadMetadataReader {runMonadMetadataReader :: KeyedValuesOf String -> a}
deriving (Functor, Applicative, Monad)
-- | Simple 'Metadata' holder.
-- There are never any matches found,
-- and all metadata (for all items)
-- comes from from the Reader-like environment at setup.
instance MonadMetadata MonadMetadataReader where
getMetadata identifier = MonadMetadataReader meta
getMatches pattern = return []
允许简单的单元测试,例如:
it "enables for a value of \"false\"" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) [("key", "false")]
enabled `shouldBe` True
it "disables for a value of \"true\"" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) [("key", "true")]
enabled `shouldBe` False
it "enables if no metadata found" $ do
let enabled = runMonadMetadataReader (unlessEnabled "key" item) []
enabled `shouldBe` True