47

今まで経験したことのない奇妙な問題に直面しています。

単体テスト (OCUnit など) を実行するために cmd+U を実行すると、実際には main.m が呼び出され、appDelegate が新たに作成され、cmd+R を押したかのようにアプリが実行されますか?

この DataLayer の背後で CoreData を使用しているためだけに質問します。私はテストで DataLayer を正常にモックアウトしていますが、実際に CoreData を呼び出す getAll メソッドを実装すると、app/xcode はマネージド オブジェクト モデルを nil にすることはできないという例外をスローします。これは理解できますが、実際に DataLayer クラスを新しくするつもりはありません。mainviewcontroller の loadView メソッドに、DataLayer の getAll メソッドを呼び出すブレーク ポイントを設定しました。これはモック オブジェクトであるため、テストでは問題にならないはずですが、実際のインスタンスを呼び出しているようです。

私の質問に戻りますが、cmd+U を押すと、最初にアプリを実行してからテストを実行しますか?

4

10 に答える 10

65

アプリケーションは実際に実行されますが、実行を防ぐために使用できるトリックがあります。

int main(int argc, char* argv[]) {
    int returnValue;

    @autoreleasepool {
        BOOL inTests = (NSClassFromString(@"SenTestCase") != nil
                     || NSClassFromString(@"XCTest") != nil);    

        if (inTests) {
            //use a special empty delegate when we are inside the tests
            returnValue = UIApplicationMain(argc, argv, nil, @"TestsAppDelegate");
        }
        else {
            //use the normal delegate 
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegate");
        }
    }

    return returnValue;
}
于 2013-03-31T01:15:27.440 に答える
20

これは、XCode 5 によって生成されたテスト クラスのデフォルトである XCTest を使用する Sulthan の回答のバリエーションです。


int main(int argc, char * argv[])
{
    @autoreleasepool {
        BOOL runningTests = NSClassFromString(@"XCTestCase") != nil;
        if(!runningTests)
        {
            return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
        }
        else
        {
            return UIApplicationMain(argc, argv, nil, @"TestAppDelegate");
        }
    }
}

これは、標準のプロジェクト レイアウトのサポート ファイルの下にある main.m に入ります。

次に、tests ディレクトリに以下を追加します。

TestAppDelegate.h


#import <Foundation/Foundation.h>

@interface TestAppDelegate : NSObject<UIApplicationDelegate>
@end

TestAppDelegate.m


#import "TestAppDelegate.h"

@implementation TestAppDelegate
@end
于 2013-12-14T20:42:43.917 に答える
11

Swift では、内部の通常の実行パスをバイパスすることを好みますapplication: didFinishLaunchingWithOptions

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    guard normalExecutionPath() else {
        window = nil
        return false
    }

    // regular setup

    return true
}

private func normalExecutionPath() -> Bool {
    return NSClassFromString("XCTestCase") == nil
}

内部のコードguardは、ストーリーボードから作成されたすべてのビューを削除します。

于 2015-12-20T17:19:42.377 に答える
5

Swift を使用している場合 (おそらく持っていない場合main.c)、次の手順を実行する必要があります。

@UIApplicationMain1:で削除AppDelegate.swift

2: 空の作成TestingAppDelegate.swift

import UIKit
class TestingAppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?
}

3: という名前のファイルを作成しますmain.swift

import Foundation
import UIKit

let isRunningTests = NSClassFromString("XCTestCase") != nil

if isRunningTests {
   UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(TestingAppDelegate))
} else {
   UIApplicationMain(C_ARGC, C_ARGV, nil, NSStringFromClass(AppDelegate))
}
于 2015-06-26T10:38:51.437 に答える
1

はい、テスト ターゲットにはアプリ ターゲットへのターゲット依存関係があるため、Cmd+U または Cmd+Shift+U を押すとアプリ ターゲットがビルドされます。

于 2013-03-30T20:23:54.577 に答える