在 yesod-tests 中使用 return "Handler Text" 的函数
Use functions that return "Handler Text" in yesod-tests
这是我的(简化)测试
it "asserts route access for valid arguments" $ do
-- ...
token <- getFlagTokenFromCsrf "1234"
get $ FlagMentorR flaggedId Flag token
statusIs 200
我有getFlagTokenFromCsrf :: Text -> Handler Text
我尝试 stack test
时得到的错误是:
Couldn't match type ‘Yesod.Core.Types.HandlerT App IO Text’
with ‘Control.Monad.Trans.State.Lazy.StateT
(YesodExampleData App) IO Text’
Expected type: Control.Monad.Trans.State.Lazy.StateT
(YesodExampleData App) IO Text
Actual type: Handler Text
(这里是 full example)
我不是 Yesod 专家,但您尝试做的事情可能没有意义:getFlagTokenFromCsrf
是一个从请求中提取一些信息的服务器端函数,因此它位于 Handler a
monad 因为这是服务器端代码的 monad。
相比之下,Yesod 测试是集成测试,从客户端断言针对您的 Application
的行为(参见 https://hackage.haskell.org/package/yesod-test-1.5.3/docs/Yesod-Test.html)。那里的功能存在于不同的 monad 中,即 YesodExample site a
代表您管理请求。这个 monad 允许您重用部分服务器代码(路由、数据类型)并管理数据库的状态,但在其他方面与服务器端操作完全不相关。
我不确定您要做什么,但如果您需要在服务器端生成一些信息,则必须找到另一种方法使其在客户端可用。
看来我正在尝试做类似的事情。即:在单元测试中尝试 运行 任意 Handler a
函数。
我尝试过和考虑过的一些方法:
我得到的最接近实际对我有用的:
import Application (handler)
spec = withApp $ do
it "" $ do
liftIO $ handler $ someHandler
尽管 it seems this calls makeFoundation
under the hood,我更希望我的处理程序 运行 在主 webapp 的上下文中而不是单独的实例中。
要在主应用程序的上下文中执行处理程序,我还尝试过:
import Foundation (unsafeHandler)
import qualified Control.Monad.Trans.State as ST
spec = withApp $ do
it "" $ do
(YesodExampleData app _ _ _) <- ST.get
liftIO $ unsafeHandler app $ someHandler
这让我遇到了这样的类型错误:
[34 of 35] Compiling Handler.FooSpec ( /path/to/test/Handler/FooSpec.hs, /path/to/.stack-work/odir/Handler/FooSpec.o )
/path/to/test/Handler/FooSpec.hs:42:31:
Couldn't match type ‘Network.Wai.Internal.Request
-> (Network.Wai.Internal.Response
-> IO Network.Wai.Internal.ResponseReceived)
-> IO Network.Wai.Internal.ResponseReceived’
with ‘App’
Expected type: App
Actual type: Network.Wai.Application
Probable cause: ‘app’ is applied to too few arguments
In the first argument of ‘unsafeHandler’, namely ‘app’
In the expression: unsafeHandler app
Failed, modules loaded: Import, Utils, Foundation, [...]
我不是很清楚 Network.Wai.Application
和 App
之间的区别,但这可能是完成这项工作的关键。
我也考虑过指定到处理程序的路由,然后可以通过 get SomeRouteR
访问它。尽管如果可以的话,我宁愿不必这样做。
- 我也在考虑将我的一些
Handler a
函数重构为 IO a
,然后我可以使用 liftIO
在处理程序和测试中执行它们。
就我所知。如果我想出更多的东西,我打算更新这个答案。我也给这个问题加了星标,所以如果有人想出更多或更好的东西,我会收到通知。
编辑:I've also asked this question on GitHub.
编辑:
我在尝试朝选项 #2 的方向进一步挖掘时发现了一些相当有前途的东西:
import Foundation (unsafeHandler)
runHandler :: Handler a -> ST.StateT (YesodExampleData App) IO a
runHandler handler = do
foundation <- getTestYesod
liftIO $ unsafeHandler foundation handler
我可以这样 运行 测试:
it "runHandler" $ do
let
testHandler :: Handler Int
testHandler = do
return 2
runHandler testHandler >>= (==? 2)
let
testHandler2 :: Handler String
testHandler2 = do
fmap show $ (Import.runDB) $ insert (def :: User)
runHandler testHandler2 >>= (==? ("UserKey {unUserKey = SqlBackendKey {unSqlBackendKey = 1}}"))
这是我的(简化)测试
it "asserts route access for valid arguments" $ do
-- ...
token <- getFlagTokenFromCsrf "1234"
get $ FlagMentorR flaggedId Flag token
statusIs 200
我有getFlagTokenFromCsrf :: Text -> Handler Text
我尝试 stack test
时得到的错误是:
Couldn't match type ‘Yesod.Core.Types.HandlerT App IO Text’
with ‘Control.Monad.Trans.State.Lazy.StateT
(YesodExampleData App) IO Text’
Expected type: Control.Monad.Trans.State.Lazy.StateT
(YesodExampleData App) IO Text
Actual type: Handler Text
(这里是 full example)
我不是 Yesod 专家,但您尝试做的事情可能没有意义:getFlagTokenFromCsrf
是一个从请求中提取一些信息的服务器端函数,因此它位于 Handler a
monad 因为这是服务器端代码的 monad。
相比之下,Yesod 测试是集成测试,从客户端断言针对您的 Application
的行为(参见 https://hackage.haskell.org/package/yesod-test-1.5.3/docs/Yesod-Test.html)。那里的功能存在于不同的 monad 中,即 YesodExample site a
代表您管理请求。这个 monad 允许您重用部分服务器代码(路由、数据类型)并管理数据库的状态,但在其他方面与服务器端操作完全不相关。
我不确定您要做什么,但如果您需要在服务器端生成一些信息,则必须找到另一种方法使其在客户端可用。
看来我正在尝试做类似的事情。即:在单元测试中尝试 运行 任意 Handler a
函数。
我尝试过和考虑过的一些方法:
我得到的最接近实际对我有用的:
import Application (handler) spec = withApp $ do it "" $ do liftIO $ handler $ someHandler
尽管 it seems this calls
makeFoundation
under the hood,我更希望我的处理程序 运行 在主 webapp 的上下文中而不是单独的实例中。要在主应用程序的上下文中执行处理程序,我还尝试过:
import Foundation (unsafeHandler) import qualified Control.Monad.Trans.State as ST spec = withApp $ do it "" $ do (YesodExampleData app _ _ _) <- ST.get liftIO $ unsafeHandler app $ someHandler
这让我遇到了这样的类型错误:
[34 of 35] Compiling Handler.FooSpec ( /path/to/test/Handler/FooSpec.hs, /path/to/.stack-work/odir/Handler/FooSpec.o ) /path/to/test/Handler/FooSpec.hs:42:31: Couldn't match type ‘Network.Wai.Internal.Request -> (Network.Wai.Internal.Response -> IO Network.Wai.Internal.ResponseReceived) -> IO Network.Wai.Internal.ResponseReceived’ with ‘App’ Expected type: App Actual type: Network.Wai.Application Probable cause: ‘app’ is applied to too few arguments In the first argument of ‘unsafeHandler’, namely ‘app’ In the expression: unsafeHandler app Failed, modules loaded: Import, Utils, Foundation, [...]
我不是很清楚
Network.Wai.Application
和App
之间的区别,但这可能是完成这项工作的关键。我也考虑过指定到处理程序的路由,然后可以通过
get SomeRouteR
访问它。尽管如果可以的话,我宁愿不必这样做。- 我也在考虑将我的一些
Handler a
函数重构为IO a
,然后我可以使用liftIO
在处理程序和测试中执行它们。
就我所知。如果我想出更多的东西,我打算更新这个答案。我也给这个问题加了星标,所以如果有人想出更多或更好的东西,我会收到通知。
编辑:I've also asked this question on GitHub.
编辑:
我在尝试朝选项 #2 的方向进一步挖掘时发现了一些相当有前途的东西:
import Foundation (unsafeHandler)
runHandler :: Handler a -> ST.StateT (YesodExampleData App) IO a
runHandler handler = do
foundation <- getTestYesod
liftIO $ unsafeHandler foundation handler
我可以这样 运行 测试:
it "runHandler" $ do
let
testHandler :: Handler Int
testHandler = do
return 2
runHandler testHandler >>= (==? 2)
let
testHandler2 :: Handler String
testHandler2 = do
fmap show $ (Import.runDB) $ insert (def :: User)
runHandler testHandler2 >>= (==? ("UserKey {unUserKey = SqlBackendKey {unSqlBackendKey = 1}}"))