Help us understand the problem. What is going on with this article?

[Swift] テストの実行時にプロダクトコードを実行しないようにする

More than 1 year has passed since last update.

テストを書いて、XCTest を実行してみるとユニットテスト以外にもアプリが起動しますよね。

他の言語のユニットテストフレームワークだとそんなことはないのですが、XCTest の場合テスト実行とともに application(application:didFinishLaunchingWithOptions) が呼ばれます。

テスト実行時にアプリの起動時のコードも実行されると無駄なログが発生したり、テストを正しく実行できません。

テスト実行中かどうかを判定する

テストの実行中かどうかはテストの実行環境にのみ存在する Class があるかどうかで判定できます。
テストの実行環境にのみ存在する Class とは XCTest Class などがあります。

    func isTesting() -> Bool {
        return NSClassFromString("XCTest") != nil // nil じゃなかったらテスト実行中
    }

2016/08/21 23:48追記

※これはXcode7まで
@mono0926 さんからコメントいただきました。↑の例とは別に判定する方法があるそうです。

    func isTesting() -> Bool {
        return NSProcessInfo.processInfo().environment["XCInjectBundle"] != nil
    }

2016/10/28 23:38追記

ProcessInfoを使う場合 Xcode8 から判別方法が変わったようです。

    func isTesting() -> Bool {
        return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
    }

テスト実行中の場合処理をスキップする

この判定を application(application:didFinishLaunchingWithOptions) の先頭において、もしテスト中だと何もしないコードを入れます。本番環境に(テスト専用の)不要なコードが入るのはイヤなので #if DEBUG など、リリース時にはコードが含まれないようにするといいと思います。

class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        #if DEBUG
        guard !isTesting() else { // テスト実行中なら
            window?.rootViewController = UIViewController()
            return true
        }
        #endif
    }
}

extension AppDelegate {
    func isTesting() -> Bool {
        return NSClassFromString("XCTest") != nil
    }
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away