iOS
XCTest
Swift
Quick
Realm

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

More than 1 year has passed since last update.

仕事で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(インスタンスメソッド)
各テストが終わった後に実行される

setUp(クラスメソッド)
クラスに存在する全てのテストが終わった後に実行される

どのようなテストなのかは基本的にメソッド名に詰め込むので、場合によっては長いメソッド名になります。

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

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") {
// テスト
}
}

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