04.FeatureSpec の始め方

FeatureSpec では、あなたは各機能(feature)のシナリオ(sinario)を書きます。

基本的な構文は、以下のようなものです。

import org.scalatest.FeatureSpec

class ExampleSpec extends FeatureSpec {

feature("ユーザーは、要素を stack の先頭から取り出すことができる") {

scenario("pop は空でない stack で実行される") (pending)

scenario("pop は空の stack で実行される") (pending)

}

}

FeatureSpec のそれぞれのシナリオは、ScalaTest の1つのテストに相当します。

この例では、シナリオの中身が「pending」になっていますが、これはまだテスト本体が実装されていないことを示しています。

このコードをコンパイルするには、コマンドラインから次のように入力してください。

$ scalac -cp scalatest-1.5.jar ExampleSpec.scala

これを実行すると、feature/sinario 構文は以下のような出力を表示します。

$ scala -cp scalatest-1.5.jar org.scalatest.tools.Runner -p . -o -s

ExampleSpec

Run starting. Expected test count is: 2

ExampleSpec:

Feature: The user can pop an element off the top of the stack

Scenario: pop は空でない stack で実行される (pending)

Scenario: pop は空の stack で実行される (pending)

Run completed in 65 milliseconds.

Total number of tests run: 0

Suites: completed 1, aborted 0

Tests: succeeded 0, failed 0, ignored 0, pending 2

All tests passed.

もしお望みなら、GivenWhenThen トレイトをミックスインし、シナリオに説明を追加することで、仕様を具体化することができます。

import org.scalatest.FeatureSpec

import org.scalatest.GivenWhenThen

class ExampleSpec extends FeatureSpec with GivenWhenThen {

feature("ユーザーは、要素を stack の先頭から取り出すことができる") {

info("一介のプログラマとして")

info("後入れ先出しの順序でアイテムを管理するために")

info("stack からアイテムを pop で取り出せるようにしたい")

scenario("pop は空でない stack で実行される") {

given("空でない stack")

when("空でない stack で pop が実行されたとき")

then("いちばん新しく格納された要素が返されなければならない")

and("その後、stack は該当する1つのアイテムを減らさなければならない")

pending

}

scenario("pop は空の stack で実行される") {

given("空の stack")

when("pop が stack で実行されたとき")

then("NoSuchElementException が投げられなければならない")

and("stack は依然空のままでなければならない")

pending

}

}

}

このバージョンの ExampleSpec を実行すると、出力レポートに説明が追加されています。

$ scala -cp scalatest-1.5.jar org.scalatest.tools.Runner -p . -o -s

ExampleSpec

Run starting. Expected test count is: 2

ExampleSpec:

Feature: ユーザーは、要素を stack の先頭から取り出すことができる

一介のプログラマとして

後入れ先出しの順序でアイテムを管理するために

stack からアイテムを pop で取り出せるようにしたい

Scenario: pop は空でない stack で実行される (pending)

Given 空でない stack

When 空でない stack で pop が実行されたとき

Then いちばん新しく格納された要素が返されなければならない

And その後、stack は該当する1つのアイテムを減らさなければならない

Scenario: pop は空の stack で実行される (pending)

Given 空の stack

When pop が stack で実行されたとき

Then NoSuchElementException が投げられなければならない

And stack は依然空のままでなければならない

Run completed in 112 milliseconds.

Total number of tests run: 0

Suites: completed 1, aborted 0

Tests: succeeded 0, failed 0, ignored 0, pending 2

All tests passed.

もうテストの実装が先延ばしにできなくなったときが、テストの書き時です。

以下に一例を示します。

import org.scalatest.FeatureSpec

import org.scalatest.GivenWhenThen

import scala.collection.mutable.Stack

class ExampleSpec extends FeatureSpec with GivenWhenThen {

feature("ユーザーは、要素を stack の先頭から取り出すことができる") {

info("一介のプログラマとして")

info("後入れ先出しの順序でアイテムを管理するために")

info("stack からアイテムを pop で取り出せるようにしたい")

scenario("pop は空でない stack で実行される") {

given("空でない stack")

val stack = new Stack[Int]

stack.push(1)

stack.push(2)

val oldSize = stack.size

when("空でない stack で pop が実行されたとき")

val result = stack.pop()

then("いちばん新しく格納された要素が返されなければならない")

assert(result === 2)

and("その後、stack は該当する1つのアイテムを減らさなければならない")

assert(stack.size === oldSize - 1)

}

scenario("pop は空の stack で実行される") {

given("空の stack")

val emptyStack = new Stack[String]

when("pop が stack で実行されたとき")

then("NoSuchElementException が投げられなければならない")

intercept[NoSuchElementException] {

emptyStack.pop()

}

and("stack は依然空のままでなければならない")

assert(emptyStack.isEmpty)

}

}

}

この例では assert を使いましたが、ScalaTest の Matcher シンタックスがお好みなら、 ShouldMatchers や MustMatchers をミックスインすることができます。

import org.scalatest.FeatureSpec

import org.scalatest.GivenWhenThen

import org.scalatest.matchers.MustMatchers

import scala.collection.mutable.Stack

class ExampleSpec extends FeatureSpec with GivenWhenThen with MustMatchers

{

feature("ユーザーは、要素を stack の先頭から取り出すことができる") {

info("一介のプログラマとして")

info("後入れ先出しの順序でアイテムを管理するために")

info("stack からアイテムを pop で取り出せるようにしたい")

scenario("pop は空でない stack で実行される") {

given("空でない stack")

val stack = new Stack[Int]

stack.push(1)

stack.push(2)

val oldSize = stack.size

when("空でない stack で pop が実行されたとき")

val result = stack.pop()

then("いちばん新しく格納された要素が返されなければならない")

result must be === 2

and("その後、stack は該当する1つのアイテムを減らさなければならない")

stack.size must be === oldSize - 1

}

scenario("pop は空の stack で実行される") {

given("空の stack")

val emptyStack = new Stack[String]

when("pop が stack で実行されたとき")

then("NoSuchElementException が投げられなければならない")

evaluating { emptyStack.pop() } must produce [NoSuchElementException]

and("stack は依然空のままでなければならない")

emptyStack must be ('empty)

}

}

}

ExampleSuite を実行してみましょう。

もう、pending になっているテストはないはずです。

$ scala -cp scalatest-1.5.jar org.scalatest.tools.Runner -p . -o -s

ExampleSpec

Run starting. Expected test count is: 2

ExampleSpec:

Feature: ユーザーは、要素を stack の先頭から取り出すことができる

一介のプログラマとして

後入れ先出しの順序でアイテムを管理するために

stack からアイテムを pop で取り出せるようにしたい

Scenario: pop は空でない stack で実行される

Given 空でない stack

When 空でない stack で pop が実行されたとき

Then いちばん新しく格納された要素が返されなければならない

And その後、stack は該当する1つのアイテムを減らさなければならない

Scenario: pop は空の stack で実行される

Given 空の stack

When pop が stack で実行されたとき

Then NoSuchElementException が投げられなければならない

And stack は依然空のままでなければならない

Run completed in 96 milliseconds.

Total number of tests run: 2

Suites: completed 1, aborted 0

Tests: succeeded 2, failed 0, ignored 0, pending 0

All tests passed.