Posted at
YesodDay 24

Yesodのテストを読み解く

More than 1 year has passed since last update.

Yesodは単体テストのための仕組みも備えています。

stackのテンプレートから作ったプロジェクトでは、 test ディレクトリの下にテスト用のファイルが格納されています。

今回はテスト関連のファイルを読み解いていきましょう。

▾ test/

▾ Handler/
CommentSpec.hs
CommonSpec.hs
HomeSpec.hs
ProfileSpec.hs
Spec.hs
TestImport.hs


Spec.hs

このファイルの中身はコメントだけです。


Spec.hs

{-# OPTIONS_GHC -F -pgmF hspec-discover #-}


このコメントは、HaskellのコンパイラであるGHCのオプションを指定していてます。

テストにおいては hspec-discover が大事で、これはテストが書かれたファイルを自動で探してくれるようにする指令です。


TestImport.hs

このファイルには、テストの中で使う関数をまとめてエクスポートしてくれています。

Model モジュールや Foundation のようなアプリケーションコードに加え、Yesod.Test のようなテスト専用のモジュールをエクスポートしています。

import部分までを抜粋します(Sqliteの場合)。


TestImport.hs

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 の中身を見てみましょう。


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



基本的な流れ

基本的には次のような流れでテストを書きます。


  1. HTTPリクエスト1を実行して

  2. 結果を検証する


    • GETであれば、レスポンスのHTMLの内容を検証

    • POSTであれば、DBの内容を検証




テスト用の設定

DBの接続先などの設定を変えたい場合は、config/test-settings.yml を書き換えます。


テストの実行

テストを実行するには次のコマンド2を実行します。stackを使っている前提です。

stack test


まとめ

非常に簡単にですが、Yesodにおけるテストを見てみました。

割と簡単にテストを書けると思います。便利ですね。





  1. request 関数がHTTPリクエストを投げる関数なのですが、これが実際にHTTPを投げているのか、それともエミュレートしているのか、分かりませんでした。。。 



  2. 一部のテストを実行する方法が分かりませんでした。。。