YesodでのFunctional Test
追記:2012/04/05: yesod-testがリリースされた。http://hackage.haskell.org/package/yesod-test
YesodはWai上に実装されているので、機能テストにはwai-testが使用できる。で、Yesod自身のテストコードはどうなってるのかなと見たところ、どうやらHspecと併用して要件を満たしているようで、同じテスト構成で構築したので備忘録がわりにメモ。
Yesodのやり方に従ったのでHspecという選択肢にしたが、別にdoctestでもQuickCheckでもなんでもいい。
├── Application.hs
├── Foundation.hs
├── Handler
│ ├── Api
│ │ └── User.hs
│ └── Root.hs
├── Import.hs
├── LICENSE
├── Sample.cabal
├── Settings
│ └── StaticFiles.hs
├── Settings.hs
├── Tests
│ ├── SampleTest
│ │ └── Handler
│ │ └── Api
│ │ └── User.hs
│ ├── SampleTest.hs
│ └── test.hs
<以下省略>
.cabalの編集。extra-source-filesにTestsディレクトリ以下のファイルを追加。Flag testの追加。testフラグが立っている場合はwai-testを使用。
<省略>
cabal-version: >= 1.6
build-type: Simple
homepage: http://Sample.yesodweb.com/
extra-source-files:
Tests/SampleTest/Handler/Api/User.hs
Tests/SampleTest.hs
Tests/test.hs
Flag test
description: Build the executable to run unit tests
default: False
Flag dev
Description: Turn on development settings, like auto-reload templates.
Default: False
Flag library-only
Description: Build for use with "yesod devel"
Default: False
library
if flag(library-only)
Buildable: True
else
Buildable: False
if flag(test)
build-depends: wai-test
<省略>
.cabalにtest-suiteを追加。
test-suite tests
type: exitcode-stdio-1.0
main-is: Tests/test.hs
cpp-options: -DTEST
extensions: TemplateHaskell
QuasiQuotes
OverloadedStrings
NoImplicitPrelude
CPP
OverloadedStrings
MultiParamTypeClasses
TypeFamilies
build-depends: base >= 4 && < 5 , yesod >= 0.10.1 && < 0.11 , yesod-core >= 0.10 && < 0.11 , yesod-static >= 0.10 && < 0.11 , yesod-default >= 0.6 && < 0.7 , clientsession >= 0.7.3 && < 0.8 , bytestring >= 0.9 && < 0.10 , text >= 0.11 && < 0.12 , template-haskell , hamlet >= 0.10 && < 0.11 , shakespeare-text >= 0.10 && < 0.11 , shakespeare-css >= 0.10.7.1 && < 0.11 , shakespeare-js >= 0.11.1 && < 0.12 , wai >= 1.1 && < 1.2 , wai-extra >= 1.1 && < 1.2 , transformers >= 0.2 && < 0.3 , monad-control >= 0.3 && < 0.4 , yaml >= 0.5 && < 0.6 , blaze-html >=0.4.3.1 && < 0.5 , SHA >=1.5.0.0 && < 1.6.0.0 , utf8-string >=0.3.7 && < 0.4 , old-time >=1.1.0.0 && < 1.2 , QuickCheck >=2.4.2 && < 3.0 , random >=1.0.1.1 && < 1.1 , test-framework >=0.5 && < 0.6 , test-framework-hunit >=0.2.7 && < 0.3 , test-framework-quickcheck2 >=0.2.12 && < 0.3 , HUnit , hspec >=0.9.1.1 && < 1.0 , wai-test >=1.1.1 && < 2.0 , wai , wai-extra >=1.1.0.1 && < 1.2 , cookie >=0.4.0 && < 0.5 , http-conduit >=1.2.6 && < 1.3 , clientsession >=0.7.4 && < 0.8 , aeson >= 0.5
ghc-options: -Wall
Tests/test.hs にエントリポイントを記述。
import Import
import Test.Hspec
import Tests.SampleTest
main :: IO ()
main = hspecX $ descriptions $ specs
Tests/SampleTest.hs で[Specs]を作成。
module Tests.SampleTest (specs) where
import Tests.SampleTest.Handler.Api.User
import Test.Hspec
specs :: [Specs]
specs =
[ userTest
]
Tests/SampleTest/Handler/Api/User.hs
module Tests.SampleTest.Handler.Api.User (userTest) where
import Prelude
import Yesod
import Application
import Test.Hspec
import Test.Hspec.HUnit ()
import Network.Wai
import Network.Wai.Test
userTest :: [Spec]
userTest = describe "SampleTest"
[ it "check request is valid" case_request_valid
]
getApp :: IO Application
getApp = do
(_,app) <- getApplicationDev return app runner :: Session () -> IO ()
runner f = getApp >>= runSession f
case_request_valid :: IO ()
case_request_valid = runner $ do
res <- request defaultRequest
{
pathInfo = ["api", "user"],
requestHeaders = [("Accept-Language", "es")]
}
assertBody "aaa" res
getApplicationDevからApplicationを取ってきてrunSessionに投げる関数を作り、テストケース内でリクエストを投げてテストを実行していく。
実行。
cabal configure -ftest --enable-tests
cabal build
cabal test