Yesodは単体テストのための仕組みも備えています。
stackのテンプレートから作ったプロジェクトでは、 test
ディレクトリの下にテスト用のファイルが格納されています。
今回はテスト関連のファイルを読み解いていきましょう。
▾ test/
▾ Handler/
CommentSpec.hs
CommonSpec.hs
HomeSpec.hs
ProfileSpec.hs
Spec.hs
TestImport.hs
Spec.hs
このファイルの中身はコメントだけです。
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
このコメントは、HaskellのコンパイラであるGHCのオプションを指定していてます。
テストにおいては hspec-discover
が大事で、これはテストが書かれたファイルを自動で探してくれるようにする指令です。
TestImport.hs
このファイルには、テストの中で使う関数をまとめてエクスポートしてくれています。
Model
モジュールや Foundation
のようなアプリケーションコードに加え、Yesod.Test
のようなテスト専用のモジュールをエクスポートしています。
import部分までを抜粋します(Sqliteの場合)。
module TestImport
( module TestImport
, module X
) where
import Application (makeFoundation, makeLogWare)
#if MIN_VERSION_classy_prelude(1, 0, 0)
import ClassyPrelude as X hiding (delete, deleteBy, Handler)
#else
import ClassyPrelude as X hiding (delete, deleteBy)
#endif
import Database.Persist as X hiding (get)
import Database.Persist.Sql (SqlPersistM, SqlBackend, runSqlPersistMPool, rawExecute, rawSql, unSingle, connEscapeName)
import Foundation as X
import Model as X
import Test.Hspec as X
import Yesod.Default.Config2 (useEnv, loadYamlSettings)
import Yesod.Auth as X
import Yesod.Test as X
-- Wiping the database
import Database.Persist.Sqlite (sqlDatabase, wrapConnection, createSqlPool)
import qualified Database.Sqlite as Sqlite
import Control.Monad.Logger (runLoggingT)
import Settings (appDatabaseConf)
import Yesod.Core (messageLoggerSource)
テスト本体
test/Handler
ディレクトリの中に置かれたファイルが、テスト本体です。
▾ test/
▾ Handler/
CommentSpec.hs
CommonSpec.hs
HomeSpec.hs
ProfileSpec.hs
HomeSpec.hs
の中身を見てみましょう。
module Handler.HomeSpec (spec) where
import TestImport
spec :: Spec
spec = withApp $ do
describe "Homepage" $ do
it "loads the index and checks it looks right" $ do
get HomeR
statusIs 200
htmlAnyContain "h1" "a modern framework for blazing fast websites"
request $ do
setMethod "POST"
setUrl HomeR
addToken
fileByLabel "Choose a file" "test/Spec.hs" "text/plain" -- talk about self-reference
byLabel "What's on the file?" "Some Content"
statusIs 200
-- more debugging printBody
htmlAllContain ".upload-response" "text/plain"
htmlAllContain ".upload-response" "Some Content"
-- This is a simple example of using a database access in a test. The
-- test will succeed for a fresh scaffolded site with an empty database,
-- but will fail on an existing database with a non-empty user table.
it "leaves the user table empty" $ do
get HomeR
statusIs 200
users <- runDB $ selectList ([] :: [Filter User]) []
assertEq "user table empty" 0 $ length users
基本的な流れ
基本的には次のような流れでテストを書きます。
- HTTPリクエスト1を実行して
- 結果を検証する
- GETであれば、レスポンスのHTMLの内容を検証
- POSTであれば、DBの内容を検証
テスト用の設定
DBの接続先などの設定を変えたい場合は、config/test-settings.yml
を書き換えます。
テストの実行
テストを実行するには次のコマンド2を実行します。stackを使っている前提です。
stack test
まとめ
非常に簡単にですが、Yesodにおけるテストを見てみました。
割と簡単にテストを書けると思います。便利ですね。