【STEP4】テスト : Scalaでコードを書く

テスト : Scalaでコードを書く
=======

この記事はScalaでコードを書く時の、セットアップや動かし方、テストなどをまとめた研修用資料です。

## テスト

テストを実行します。

※ コマンドプロンプトから実行します。eclipseはエディタとして使用し、eclipseから実行することはありません。

### コマンドプロンプトから実行

- コマンドプロンプロトを起動し、プロジェクトが存在するディレクトリまで移動します。

```
cd [プロジェクトのルートディレクトリ]
```

- activatorを起動します。

Windowsの場合

```
activator.bat
```

Macの場合

```
./activator
```

ここから一緒です。

- テストコードはこんな感じです。

```scala:HelloSpec.scala
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers

class HelloSpec extends FlatSpec with ShouldMatchers {
  "Hello" should "have tests" in {
    true should be === true
  }
}
```

抜き出して簡単に説明します。

```
"Hello" should "have tests" in {
  true should be === true
}
```

1行目がテストケースの説明です。ここにどのようなテストをしたいのかという、テスト内容を記載します。
**Hello(＝Helloクラス)**は、**テストを持っているべき**、と読みます。

```
true should be === true
```

上記の2行目が実際のテストコードです。
そのまま英文のように読むことが出来ます。
***true should be true***、ということで必ずテストが成功することが分かります。

- それではTestクラスを、「test」コマンドで実行してみましょう。

```
> test
```

下記のように、最後に「All tests passed」が表示されれば成功です。
「succeeded 」が1で、「failed」が0になっていることが分かります。

```
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] Run completed in 203 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 4 s, completed 2015/02/24 9:00:00
>
```

- 試しにテストを失敗させてみましょう。下記のようにテストコードを変更します。

```scala:HelloSpec.scala
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers

class HelloSpec extends FlatSpec with ShouldMatchers {
  "Hello" should "have tests" in {
    true should be === false
  }
}
```

***true should be false***、というのは必ず失敗するはずです。

- 再度、「test」コマンドで実行してみます。

```
> test
```

下記のように、最後に「Tests unsuccessful」が表示され失敗します。
「succeeded 」が0で、「failed」が1になっていることが分かります。

```
[info] HelloSpec:
[info] Hello
[info] - should have tests *** FAILED ***
[info]   true was not equal to false (HelloSpec.scala:6)
[info] Run completed in 155 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***
[error] Failed tests:
[error]         HelloSpec
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 2 s, completed 2015/02/24 9:01:00
>
```

- STEP 3で覚えたように、「~」を頭につけて再度***true should be true***に修正します。

```
> ~test
```

今度は成功しました。

```
2. Waiting for source changes... (press enter to interrupt)
[info] Compiling 1 Scala source to C:\workspace\minimal-scala\target\scala-2.11\test-classes...
[warn] there were two deprecation warnings; re-run with -deprecation for details
[warn] one warning found
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] Run completed in 125 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 1 s, completed 2015/02/24 9:02:00
3. Waiting for source changes... (press enter to interrupt)
```

- テストケースを追加してみましょう。**it**を**"Hello"**の代わりに使用することが出来ます。

```scala:HelloSpec.scala
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers

class HelloSpec extends FlatSpec with ShouldMatchers {
  "Hello" should "have tests" in {
    true should be === true
  }
  
  it should "1 + 1 = 2" in {
    1 + 1 should be === 2
  }
}
```

下記のような結果になるはずです。

```
[info] HelloSpec:
[info] Hello
[info] - should have tests
[info] - should 1 + 1 = 2
[info] Run completed in 141 milliseconds.
[info] Total number of tests run: 2
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
[info] All tests passed.
[success] Total time: 1 s, completed 2015/02/24 9:03:00
4. Waiting for source changes... (press enter to interrupt)
```

## クラスのメソッドのテスト例

試しにクラスのテストも書いてみましょう。

- 新規に下記クラスのコードを作成します。

```scala:Calculate.scala
package com.example

class Calculate {
  def add(x: Int, y: Int): Int = {
    x + y
  }
}

```

- テストコードからCalculateクラスのaddメソッドを呼び出してテスト出来ます。

```scala:AddSpec.scala
import org.scalatest._
import com.example.Calculate

class AddSpec extends FlatSpec with MustMatchers {
  "Calculate" should "addメソッドの 1 + 2 = 3" in {
    val calculate = new Calculate()
    val result = calculate.add(1, 2)
    result must be === 3
  }
}
```

## (余談)

```scala:HelloSpec.scala
import org.scalatest._
import org.scalatest.matchers.ShouldMatchers

class HelloSpec extends FlatSpec with ShouldMatchers {
  "Hello" should "have tests" in {
    true should be === true
  }
}
```

上記のコードは下記のように書くことも出来ます。

```scala:HelloSpec.scala
import org.scalatest._

class HelloSpec extends FlatSpec with MustMatchers {
  "Hello" should "have tests" in {
    true must be === true
  }
}
```

***should***より***must***の方が少し短くて嬉しいかも知れません。