XCTestと比較しつつQuickについて説明する

仕事でQuickを使ってユニットテストを書いてみてなかなかいいなと思ったので、XCTestと比較しつつQuickについて説明しようと思います。

ここで使用しているコードは以下のGitHubから抜粋しています。下記GitではRealm周りのテストをXCTest, Quickを使って書いています。
XCTestに関係なくQuickとNimbleでこんなことできるよ的なサンプルはこれから随時追加していく予定です。
[akatsuki174/QuickSample](https://github.com/akatsuki174/QuickSample)

# [XCTest](https://developer.apple.com/library/prerelease/ios/documentation/DeveloperTools/Conceptual/testing_with_xcode/chapters/01-introduction.html)とは

皆さんご存知の通り、Xcode5で導入されたユニットテストフレームワークです。

# [Quick](https://github.com/Quick/Quick)とは

Swift, Objective-CのためのBDD(ビヘイビア駆動開発)テストフレームワークです。
[RSpec](https://github.com/rspec/rspec), [Specta](https://github.com/specta/specta), [Ginkgo](https://github.com/onsi/ginkgo)の影響を受けています。
最近[日本語ドキュメント](https://github.com/Quick/Quick/tree/master/Documentation/ja)ができました。
matcherはNimbleを使っています。Swift, Objective-Cの両方で使えます。[Cedar](https://github.com/pivotal/cedar)の影響を受けているようです。

# 比較

## テストメソッドの書き方

### XCTestの場合

```swift
import XCTest
@testable import <プロジェクト名>

class <クラス名> : XCTestCase {
  func testHoge() {
      // テスト
  }
}
```

基本形はこれです。場合によって以下のメソッドを使ったりします。

| メソッド | 意味 |
|:------------|:------------|
| setUp(クラスメソッド)|クラスに存在する全てのテストが始まる前に実行される|
| setUp(インスタンスメソッド)|各テストが始まる前に実行される|
| tearDown(インスタンスメソッド)|各テストが終わった後に実行される|
| tearDown(クラスメソッド)|クラスに存在する全てのテストが終わった後に実行される|

どのようなテストなのかは基本的にメソッド名に詰め込むので、場合によっては長いメソッド名になります。
サンプルコードから抜粋するとこんなかんじです。

```swift
func testDBManagerTest_findAllMethod_whenNotExistData_output0Data() {
  // テスト
}
```

左ペインにはこのように表示されます。
![スクリーンショット 2016-02-27 11.50.12.png](https://qiita-image-store.s3.amazonaws.com/0/100736/658999c5-70ae-1650-8fb3-3edd6ced71dc.png)


### Quickの場合

```swift
import Quick
import Nimble
@testable import <プロジェクト名>

class <クラス名>: QuickSpec {
  override func spec() {
    describe("describe text") {
      context("context text") {
        it("it text") {
          // テスト
        }
      }
    }
  }
}

```

基本形はこれです。ただしdescribe, context, itはなくても構いません。describe, contextに関しては入れ子にして複数使っても構いません。describeの引数にはクラスと関数を、contextの引数にはある条件下での動作を、itの引数には期待される結果を書きます。
公式によると、「厳密には context キーワードは describeと同じですがテストを理解しやすくなるので使い分けるとよいです。」とのことです。

また、場合によって以下のメソッドを使ったりします。

| メソッド | 意味 |
|:------------|:------------|
| beforeSuite |クラスに存在する全てのテストが始まる前に実行される|
| beforeEach |各テストが始まる前に実行される|
| afterEach |各テストが終わった後に実行される|
| afterSuite |クラスに存在する全てのテストが終わった後に実行される|

サンプルコードから抜粋するとこんなかんじです。

```swift
describe("DBManager test") {
  describe("findAll method") {
    context("when not exist data") {
      it("output 0 data") {
        // テスト
      }
    }
  }
}
```

左ペインにはこのように表示されます。
![スクリーンショット 2016-02-26 0.47.11.png](https://qiita-image-store.s3.amazonaws.com/0/100736/9109100f-5c39-af02-4561-878debf83176.png)

## テストの書き方

とりあえず今回は実際の値と予想していた値が等しいことを確かめるテストを取り上げて比較してみようと思います。


### XCTestの場合

```swift
XCTAssertEqual(results.count, 0, "Expect \(results.count) to equal 0")
```

第一引数に実際の値、第二引数に期待値、第三引数にエラーだった時に表示するメッセージを入れます。

### Quickの場合

```swift
expect(results.count).to(equal(0))
```

expectの引数に実際の値、equalの引数に期待値を入れます。
エラーだった時に表示するメッセージを用意しなくてもデフォルトで出力されるテンプレートがあるので、特別書く必要はありません。
※エラーメッセージをカスタマイズすることもできます。

## テストが失敗した時の表示

### XCTestの場合

![スクリーンショット 2016-02-27 12.22.07.png](https://qiita-image-store.s3.amazonaws.com/0/100736/da6ae53b-4234-7157-a0a5-6be9f8581c00.png)

### Quickの場合

![スクリーンショット 2016-02-27 12.24.53.png](https://qiita-image-store.s3.amazonaws.com/0/100736/7996ebb4-bc64-d98c-6568-2e38baa2924d.png)

# 比べてみてQuickいいなと思ったポイント

## エラーメッセージをわざわざ書かなくていいのは楽

テストを大量に書くとなると少しでも手間が省けるのはだいぶうれしいです。

## テストのまとまりがわかりやすい

サンプルコードではupdateメソッドのテストを2つのパターンに分けて書いています。
これをXCTestで書くと下記のようになるわけですが、

```swift
func testDBManagerTest_updateMethod_whenAddNewData_newDataIsInserted() {
  // テスト
}
    
func testDBManagerTest_updateMethod_whenAddExistngData_theDataIsUpdated() {
  // テスト
}
```

Quickで書くとこうなります。

```swift
describe("update method") {
  context("when add new data") {
    // テスト
  }
                
  context("when add existing data") {
    // テスト
  }
}
```

一つのテストクラスで一つのメソッドについてテストしている分には何も変わらないでしょうが、複数のメソッドを同じテストクラス内でテストしているときは階層がメソッドごとに分かれていたほうが見やすくて良いと思いました。