MILLEN BOX

音楽好きの組み込みソフトエンジニアによるプログラミング(主にiOSアプリ開発)の勉強の記録

〜Tests.swiftって何?XCTestでの単体テストのススメ [swift1.2]

初アプリリリース完了の熱冷めやらぬ間に更新。(しつこい)
リリースした時の記事をリンクも貼っておきますね。

初アプリ!RPNConverterをリリースしました! - MILLEN BOX

さて、今日はXcode単体テストに挑戦したいと思います。

Project内に (Project名)Tests というフォルダの中に、 (Project名)Tests.swift というファイルがあることを見て見ぬフリしている方も多いと思います。(私です。)
実は、このファイルにテスト用の関数を追記して、テスト対象関数の自動テストをすることが可能なのです!(このテストを単体テストといいます。)
また、Xcode内で動作するこのテストツールの名前はXCTestと言います。

ProjectのViewController内に以下のような関数を作成しました。
この editCount() が今回のテスト対象の関数です。

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    /**
    表示用にカウント数を10進数の桁毎に数値を分割する。表示桁数を超えた場合にはゼロに戻します。
    
    :param: count:カウント数
    :param: digitNum:変換する桁数
    :returns: digitArray:変換結果を入れる配列
    */
    func editCount(var count :Int, digitNum :Int) -> [Int] {
 
        var digitArray = [Int]()
        
        for index in 0 ... (digitNum) {
            let tmpDec = pow(10.0, Double(digitNum - index))
            if index != 0 {digitArray.append(count / Int(tmpDec))}
            count = count % Int(tmpDec)
        }
    
        return digitArray
    }
    
}

次は (Project名)Tests.swift (今回の例では RendaTests.swift )を開き、テスト用関数( testEditCount1 )を追加します。初期状態で記載済みの関数については現状無視して下さい。

import UIKit
import XCTest

class RendaTests: XCTestCase {
    
    override func setUp() {
        super.setUp()
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }
    
    override func tearDown() {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        super.tearDown()
    }
    
    func testExample() {
        // This is an example of a functional test case.
        XCTAssert(true, "Pass")
    }
    
    func testPerformanceExample() {
        // This is an example of a performance test case.
        self.measureBlock() {
            // Put the code you want to measure the time of here.
        }
        
    }

    //ここからが追加したテスト関数
    func testEditCount1() {
        let testViewController: ViewController = ViewController()       //ViewControllerクラスをインスタンス化
        let result = testViewController.editCount(9999, digitNum: 4)    //テストしたいメソッドを呼び出し
        XCTAssertNotNil(result)                                         //テスト結果がnilでないか
        XCTAssertEqual(result, [9,9,9,9], "result is [9,9,9,9]")        //テスト結果(第1引数)が期待値(第2引数)と等しいか
    }
    
}

ここまで出来たらいよいよテストの実行です。。
Navigatorの左から5番目のアイコンをクリックします。
f:id:anthrgrnwrld:20150805210048p:plain

そして (Project名)Tests のよこに出現する▶︎をクリックしましょう。テストがスタートします。
f:id:anthrgrnwrld:20150805210518g:plain

無事テストがサクセスしました。もし設計した関数に不具合があったりすると、ここでFailになります。(勿論正確にテスト設計した場合ですが...)

今回は、(テスト対象の関数の作成)→(テスト関数の作成)という順番で説明しましたが、本来は(テスト関数の作成)→(テストをパスするように関数を作成)と行う方がよいです。というかそうでなければならないのでしょう。

テストはめんどくさいです。しかしXcodeにはこんな便利ツールがあるので、ちょっと単体テストへの敷居が低くなりました。