Yesod /持续测试支架图案

时间:2013-01-18 05:48:08

标签: testing haskell entity persistent yesod

我对Haskell很新,所以我无法吸收Yesod中使用的所有高级功能,例如type instancesequality constraints。我试图在Yesod的测试框架中实现bracket pattern以获得setUp / tearDown功能。这是我到目前为止所得到的(通过编辑更新):

module FishMother where

import Control.Exception.Lifted

import TestImport
import Database.Persist
import Database.Persist.GenericSql

import Model

insertYellowfinTuna :: OneSpec Connection FishId
insertYellowfinTuna = runDB . insert $ Fish "Yellowfin Tuna"

deleteFish :: FishId -> OneSpec Connection ()
deleteFish = runDB . delete

withYellowfinTuna :: FishId -> OneSpec Connection ()
withYellowfinTuna = bracket insertYellowfinTuna deleteFish

编译错误如下:

tests/FishMother.hs:18:21:
    Couldn't match type `FishId
             -> Control.Monad.Trans.State.Lazy.StateT
                  (Yesod.Test.OneSpecData Connection) IO ()'
          with `Key SqlPersist Fish'
    Expected type: FishId -> OneSpec Connection ()
      Actual type: (FishId
            -> Control.Monad.Trans.State.Lazy.StateT
             (Yesod.Test.OneSpecData Connection) IO ())
           -> Control.Monad.Trans.State.Lazy.StateT
            (Yesod.Test.OneSpecData Connection) IO ()
    In the return type of a call of `bracket'
    In the expression: bracket insertYellowfinTuna deleteFish
    In an equation for `withYellowfinTuna':
    withYellowfinTuna = bracket insertYellowfinTuna deleteFish

我做错了什么?

1 个答案:

答案 0 :(得分:3)

在重新阅读问题后,我认为简单的答案是使用a lifted bracket,它将处理所有变压器问题。我也会留下原来的答案,因为它可能会更深入地了解正在发生的事情。


这种情况下的问题是使用liftIO。我们来看一下类型签名:

liftIO :: MonadIO m => IO a -> m a

这意味着您可以执行任意I / O操作(例如,从文件读取)并在允许执行I / O的任何monad中运行它,例如数据库monad。但是,您尝试执行的操作恰恰相反:将数据库monad操作作为普通的I / O操作运行。这不能直接完成,因为数据库操作依赖于额外的上下文 - 特别是数据库连接 - IO monad不提供。

那么如何将数据库操作转换为IO操作?我们必须解开。展开是 monad变换器的常见活动,可以将其视为彼此叠加的图层。提升(如在liftIO中)允许您从较低层采取动作并将其向上移动到更高层。展开需要一层。由于你打开的方式取决于特定的变压器,每个变压器都有自己的展开功能。

对于Persistent,您可以使用withSqliteConn或后端的等效内容,有关详细信息,请参阅Persistent chapter中的概要。