【发布时间】:2016-09-07 04:11:38
【问题描述】:
我有一个 Yesod 应用,其类型为:
data App = App
{ appSettings :: AppSettings
, appStatic :: Static
, appConnPool :: ConnectionPool
, appHttpManager :: Manager
, appLogger :: Logger
, appStripe :: forall a. ((FromJSON (StripeReturn a)), Typeable (StripeReturn a))
=> StripeConfig
-> StripeRequest a
-> IO (Either StripeError (StripeReturn a))
}
还有一个辅助函数
stripe :: (FromJSON (StripeReturn a), Typeable (StripeReturn a))
=> StripeRequest a
-> Handler (Either StripeError (StripeReturn a))
stripe req = do
f <- appStripe <$> getYesod
c <- appStripeConfig . appSettings <$> getYesod
liftIO $ f c req
在多个处理程序中使用。 (App 的 appStripe 字段从未在任何处理程序中直接引用。)在makeFoundation 中,所有内容都作为脚手架,除了appStripe 字段用来自stripe-haskell 库的Web.Stripe.stripe 填充.
在我的测试中,我希望能够模拟对 Stripe 的调用,所以我有以下功能:
withStripeExpecting :: (FromJSON (StripeReturn a), Typeable (StripeReturn a))
=> StripeRequest a
-> Either StripeError (StripeReturn a)
-> YesodExample App ()
-> YesodExample App ()
withStripeExpecting _expectedReq res = withStateT $ \yed -> yed {yedSite = f (yedSite yed)}
where f app = app {appStripe = mock}
mock :: Typeable (StripeReturn b)
=> StripeConfig
-> StripeRequest b
-> IO (Either StripeError (StripeReturn b))
mock _ _actualReq = do
-- assert actualReq matches expectedReq (in IO???)
return $ case cast res of
Just a -> a
Nothing -> error "Stripe return types don’t match in mock."
我在测试用例中使用:
spec :: Spec
spec = withApp $ do
describe "create" $ do
it "returns a 201" $ do
-- a bunch of set-up elided
withStripeExpecting stripeReq (Right stripeRes) $ do
requestWithSubject "auth0|fake" $ do
setMethod "POST"
setUrl $ SubscriptionPlansR walletId
setRequestBody encoded
addRequestHeader (H.hContentType, "application/json")
statusIs 201
编译并运行,但抛出错误StripeError {errorType = InvalidRequest, errorMsg = "Invalid API Key provided: ", errorCode = Nothing, errorParam = Nothing, errorHTTP = Just UnAuthorized},表明它正在运行真正的条带 IO 操作而不是模拟。
如何在测试期间更改App 的字段,以便被测试的处理程序使用它?
【问题讨论】:
-
你的 withStripeExpecting 块或 withApp 初始化是否发生错误?我建议修改 withApp 函数(它是脚手架的)