LoginSignup
6
3

More than 5 years have passed since last update.

StoryboardのViewControllerを生成するExtensionのテストを書く

Last updated at Posted at 2017-10-08

概要

使うと手放せなくなるSwift Extension集 (Swift3版)に書かれているStoryboardのViewControllerを生成が便利なのでプロジェクトに取り入れました。
その際にテストを書いてみたので備忘録として記載。

ちなみにViewControllerの生成がこんな感じで書けるようになるExtensionです。

使うと手放せなくなるSwiftExtension集(Swift3版)より
MyViewController.instantiate() // Storyboardファイルとクラスが同じ名前の場合
MyViewController.instantiate(withStoryboard: "MyStoryboard")

使い方自体は使うと手放せなくなるSwift Extension集 (Swift3版)をご参照ください。

書くにあたって以下の記事を参考にしました。ありがとうございます。

結論

https://github.com/TakkuMattsu/StoryBoardInstantiatableUnittestに書いたテストコードをあげています。
ややゴリ押し+条件があります。

2017/10/10 追記
@okuderap さんからのアドバイスを反映
(以前のコードとの差分はこちら)

class UIViewController_StoryboardTests: 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 test_ストーリボートからViewController作成() {
        // info.plistにViewControllerが置いてる場所のパスがあるのでそれを取得
        guard let infolist: [String : Any] = Bundle(for: UIViewController_StoryboardTests.self).infoDictionary, let vcPath =  infolist["Source Directory"] as? String else {
            XCTFail()
            return
        }
        /// 除外リスト
        let excludeList = [
            ViewController.className          // 起動Storyboardと結びついているので除外
        ]
        /// テスト
        let files = viewControllerFileNames(atPath: vcPath)
        print("ViewController数:\(files.count) うち除外:\(excludeList.count)")
        let testList = files.filter { (file) -> Bool in
            // 除外リスト
            excludeList.map({ (excludeClassName) -> Bool in
                file != "\(excludeClassName).swift"
            }).reduce(true, { (result, bool) -> Bool in
                result && bool
            })
            }.map { (file) in
                let fileName = (file as NSString).deletingPathExtension
                print("\(fileName)生成テスト")
                let className = Bundle.main.infoDictionary!["CFBundleName"] as! String + "." + fileName
                let aClass = NSClassFromString(className) as! UIViewController.Type
                let vc = aClass.instantiate()
                XCTAssertNotNil(vc, "\(className)")
        }
        // 全てテストできているか
        XCTAssertTrue(testList.count == (files.count - excludeList.count))
        print("実施:\(testList.count)")
        print("除外:\(excludeList.count)")
        excludeList.forEach { (file) in
            print("- \(file)")
        }
    }
}

private extension UIViewController_StoryboardTests {

    /// 指定ディレクトリ内の「ViewController.swift」が含まれているファイル名を取得
    ///
    /// - Parameter dirPath: ディレクトリパス
    /// - Returns: 「ViewController.swift」が含まれているファイル名の配列
    func viewControllerFileNames(atPath dirPath: String) -> [String] {

        var vcFileNames = [String]()
        var isDir: ObjCBool = false
        let vcSuffix = "ViewController.swift"
        let fileExists = FileManager.default.fileExists(atPath: dirPath, isDirectory: &isDir)

        if !fileExists {
            XCTFail("dirPath does not exist.")
        }
        if !isDir.boolValue {
            XCTFail("dirPath is not a directory.")
        }

        if let paths = FileManager.default.enumerator(atPath: dirPath) {
            while let path = paths.nextObject() as? String {
                if path.hasSuffix(vcSuffix) {
                    let fileName = (path as NSString).lastPathComponent
                    vcFileNames.append(fileName)
                }
            }
        }
        return vcFileNames
    }
}
テスト結果
Test Suite 'UIViewController_StoryboardTests' started at 2017-10-08 23:05:31.800
Test Case '-[StoryBoardInstantiatableUnitTestTests.UIViewController_StoryboardTests test_ストーリボートからViewController作成]' started.
ViewController数:5 うち除外:1
AoiChangViewController生成テスト
HinataChangViewController生成テスト
KaedeSanViewController生成テスト
KokonaChangViewController生成テスト
実施:4
除外:1
- ViewController
Test Case '-[StoryBoardInstantiatableUnitTestTests.UIViewController_StoryboardTests test_ストーリボートからViewController作成]' passed (0.067 seconds).
Test Suite 'UIViewController_StoryboardTests' passed at 2017-10-08 23:05:31.871.
         Executed 1 test, with 0 failures (0 unexpected) in 0.067 (0.071) seconds
Test Suite 'StoryBoardInstantiatableUnitTestTests.xctest' passed at 2017-10-08 23:05:31.873.
         Executed 1 test, with 0 failures (0 unexpected) in 0.067 (0.074) seconds
Test Suite 'All tests' passed at 2017-10-08 23:05:31.876.
         Executed 1 test, with 0 failures (0 unexpected) in 0.067 (0.080) seconds
** TEST SUCCEEDED **

補足

やってること

  1. info.plistに書かれたViewControllerが配置してあるディレクトリを検索し、ViewControllerクラスの一覧を取得(getAllFile()を読んでいる箇所)
  2. 除外リストのViewControllerを抜いてクラス名からクラスを作成
  3. 作成したクラスのinstantiate()を呼んでテスト実施

条件について

まとめ

使うと手放せなくなるSwift Extension集 (Swift3版)にはめちゃくちゃ役立つTipsがたくさんあります。プロジェクトにあったものを選んで利用することで効率があがると思います。

6
3
2

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
6
3