Documentation

You are viewing the documentation for the 2.2.x release series. The latest stable release series is 2.4.x.

§アプリケーションのテスト

アプリケーションのテストを書くことは、複雑な工程になりがちです。
PlayFrameworkでは、標準でテストフレームワークをサポートしており、ヘルパーやアプリケーションスタブを用意しているため、簡単にテストを組むことができます。

§概要

テストのソースファイルは test フォルダに配置します。
2つのテンプレートとして使えるサンプルファイルが test フォルダに置いてあるので、参照してみてください。

テストを実行する際、 Play の場合コンソールから実行できます。

SBT でテストを実行する際は、 testing SBT に詳細が記載されています。

§specs2 を使う

Play の標準的なテストでは、 specs2 を利用します。
spec2 のテストでは、異なったコードパスのテストを実行する例を、まとめて記述します。

Specificationtrait を継承した仕様で should/in のフォーマットを使って記述します。:

Unable to find label scalatest-helloworldspec in source file code/HelloWorldSpec.scala

仕様は IntelliJ IDEA ( Scala pluginを利用 ) か Eclipse ( Scala IDEを利用 ) で実行することができます。 詳しくは IDE page を見てください。

メモ:presentation compiler のバグで、 Eclipse でコーディングする場合、特定のフォーマットで書く必要があります。

Eclipse では以下のように書きます。

package models // このファイルは、「models」というディレクトリに配置されている必要があります。

import org.specs2.mutable._
import org.specs2.runner._
import org.junit.runner._

@RunWith(classOf[JUnitRunner])
class ApplicationSpec extends Specification {
  ...
}

§Matchers

テスト例を使った際、テスト例の結果を返さなければいけません。大体、 must という宣言がよく使われます。

"Hello world" must endWith("world")

must に続く表現は、 matchers と呼ばれます。
matchers はテスト例の結果を成功か失敗かで返します。結果を返さない場合、テスト例はコンパイルされません。

最も使いやすい matchers は、match results です。
等しいかどうかや Option や Either の結果を判定したり、例外が投げられたかどうかをチェックします。

他にも XML や JSON を比較するテストの optional matchers などもあります。

§Mockito

モックは外部の依存関係から独立したユニットテストを行う際に用います。
例えば、外部の DataService クラスに依存している場合、 DataService オブジェクトのインスタンスを作らなくても、モックを使ってデータを提供できます。

Mockito は、標準の mocking library として、 spec2 に組み込まれています。

Mockito は以下のように使います。

import org.specs2.mock._

ビルドに library dependency を追加します。

Mockito を使えば、次のように参照をモックに向けさせられます。

Unable to find label scalaws-mockito in source file code/ExampleMockitoSpec.scala

モックは、パブリックなメソッドに対してのテストとしてとても便利です。
モックオブジェクトとプライベートメソッドの組み合わせでも可能ですが、大変です。

§モデルのユニットテスト

Play はモデルを使う際に、特定のデータベースアクセス層を必要としません。
しかしながら、アプリケーションが Anorm や Slick を使っていた場合、内部的にモデルからデータベースへの参照が頻繁に行われるでしょう。

import anorm._
import anorm.SqlParser._

case class User(id: String, name: String, email: String) {
   def roles = DB.withConnection { implicit connection =>
      ...
    }
}

モデルのユニットテストを行うにあたり、 roles メソッドを使うことでモック化することが出来ます。

一般的なアプローチでは、モデルをデータベースから隔離し、ロジックに集中させ、リポジトリ層を利用して抽象的にデータベースアクセスを行います。

case class Role(name:String)

case class User(id: String, name: String, email:String)
trait UserRepository {
  def roles(user:User) : Set[Role]
}
class AnormUserRepository extends UserRepository {
  import anorm._
  import anorm.SqlParser._

  def roles(user:User) : Set[Role] = {
    ...
  }
}

そして、サービスを経由してアクセスします。

class UserService(userRepository : UserRepository) {

  def isAdmin(user:User) : Boolean = {
    userRepository.roles(user).contains(Role("ADMIN"))
  }
}

この方法で、 UserRepository を参照しサービス層へ渡すことで、 isAdmin メソッドをモックでテストすることができます。

Unable to find label scalatest-userservicespec in source file code/UserServiceSpec.scala

§コントローラーのユニットテスト

Play ではコントローラーはオブジェクトとして定義されるため、ユニットテストでトリッキーなことができます。
Play では、 getControllerInstance を使って、 dependency injection でユニットテストを簡単に出来ます。
コントローラーをテストするトリッキーな他の方法は、 明示的に型付けられた自己参照 上の trait をコントローラーに使います。

Unable to find label scalatest-examplecontroller in source file code/ExampleControllerSpec.scala

そして、 trait のテストを追加します。

Unable to find label scalatest-examplecontrollerspec in source file code/ExampleControllerSpec.scala

Next: Writing functional tests


このドキュメントの翻訳は Play チームによってメンテナンスされているものではありません。 間違いを見つけた場合、このページのソースコードを ここ で確認することができます。 ドキュメントガイドライン を読んで、お気軽にプルリクエストを送ってください。