106
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2016-02-27

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

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

XCTestとは

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

Quickとは

Swift, Objective-CのためのBDD(ビヘイビア駆動開発)テストフレームワークです。
RSpec, Specta, Ginkgoの影響を受けています。
最近日本語ドキュメントができました。
matcherはNimbleを使っています。Swift, Objective-Cの両方で使えます。Cedarの影響を受けているようです。

比較

テストメソッドの書き方

XCTestの場合

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

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

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

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

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

func testDBManagerTest_findAllMethod_whenNotExistData_output0Data() {
  // テスト
}

左ペインにはこのように表示されます。
スクリーンショット 2016-02-27 11.50.12.png

Quickの場合

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 クラスに存在する全てのテストが終わった後に実行される

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

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

左ペインにはこのように表示されます。
スクリーンショット 2016-02-26 0.47.11.png

テストの書き方

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

XCTestの場合

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

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

Quickの場合

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

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

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

XCTestの場合

スクリーンショット 2016-02-27 12.22.07.png

Quickの場合

スクリーンショット 2016-02-27 12.24.53.png

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

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

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

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

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

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

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

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

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

106
87
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
106
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?