[英]How do I modify my Yesod app during a test?
我有一個類型為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
在多個處理程序中使用。 (該appStripe
所述的場App
是從未在任何處理直接引用。)在makeFoundation
,一切都作為腳手架,不同之處在於appStripe
字段與填充在Web.Stripe.stripe
從stripe-haskell
庫。
在我的測試中,我希望能夠模擬對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
的字段,以便被測試的處理程序使用該字段?
我在Yesod的Google Group上發布了對此問題的參考,並收到Yesod的發起人Michael Snoyman的以下答復 :
IIUC,您只需要在代碼的其他位置覆蓋該字段即可。 以腳手架站點為例,我在這里覆蓋:
根據該建議,需要對Yesod.Test
模塊進行一些重做,以將對Yesod.Test
控制通過線程傳遞到測試用例。 這些更改已在GitHub的yesod存儲庫中的“ Pull Request#1274 ”中捕獲。
有了yesod-test的修改版本,我能夠用以下三行替換Michael Snoyman指出的行:
mocks <- newEmptyMVar
let foundation' = foundation { appStripe = mockStripe mocks }
return (foundation', logWare, mocks)
我還向TestImport
模塊添加了以下支持定義:
data StripeMock = forall a. Typeable (StripeReturn a)
=> StripeMock
{ stripeReq :: StripeRequest a
, stripeRet :: Either StripeError (StripeReturn a)
}
type Mocks = MVar StripeMock
type Yex = YesodExample App Mocks
mockStripe :: (Typeable (StripeReturn b))
=> Mocks
-> StripeConfig
-> StripeRequest b
-> IO (Either StripeError (StripeReturn b))
mockStripe mocks _ _actualReq = do
(StripeMock _expectedReq res) <- takeMVar mocks
-- assert actualReq matches expectedReq (in IO???)
return $ case cast res of
Just a -> a
Nothing -> error "Stripe return types don’t match in mock."
stripeExpects :: (FromJSON (StripeReturn a), Typeable (StripeReturn a))
=> StripeRequest a
-> Either StripeError (StripeReturn a)
-> Yex ()
stripeExpects expectedReq res = do
mocks <- getMocks
putMVar mocks $ StripeMock expectedReq res
stripeExpects
幫助器函數將替換為withStripeExpecting
,並且不會像withStripeExpecting
那樣包裝請求。
如拉取請求中所示,我正在嘗試將這種容量包含在yesod-test軟件包中。 如果對此有所幫助,我將更新此答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.