web-dev-qa-db-ja.com

Xcode:TEST vs DEBUGプリプロセッサマクロ

ユニットテストを使用して新しいプロジェクトを作成する場合、Xcodeはテストスキームのビルド構成をデバッグに設定します(実行スキームと同じ)。

実行(コマンドR)とテスト(コマンドU)のスキームを区別する必要がありますか?

つまり、Testという新しいビルド構成を作成し、それにプリプロセッサマクロTEST = 1を追加して、代わりにそれをテストスキームのビルド構成として使用する必要がありますか?または、実行とテストの両方をデバッグとして保持する必要がありますか?

私はRuby/Railsのバックグラウンドを持っています。通常、テスト、開発、および実稼働環境があります。デバッグは開発のようであり、リリースは本番のようであるように見えますが、テストが欠落しているため、テストを追加することには意味があると考えています。

コメント?意見?提案?

私はテストのために何かをコンパイルしたいので、特にこれを求めています:

#ifdef TEST
// Do something when I test.
#endif

これをデバッグ用にコンパイルしても問題ないと思います。だから、私は本当にすることができます:

#ifdef DEBUG
// Do something when I run or test.
#endif

しかし、私は今のところ、テストのためだけにそれを行うつもりです。だから、デバッグとテストを区別する必要があると思っていますが、Xcodeがデフォルトでそれを行わないのはなぜですか? Appleはそれらを区別すべきではないと思いますか?

35
ma11hew28

テストビルド構成を作成する代わりに、私は:

  1. Tests-Prefix.pchファイルを作成しました:

    #define TEST 1
    #import <SenTestingKit/SenTestingKit.h>
    #import "CocoaPlant-Prefix.pch"
    
  2. testsターゲットのビルド設定のPrefixヘッダーフィールドにパスを入力しました。

  3. 作成したMyAppDefines.hというファイルの先頭に次のコードを追加し、MyApp-Prefix.pchにインポートしました。

    #ifdef TEST
    #define TEST_CLASS NSClassFromString(@"AppDelegateTests") // any test class
    #define BUNDLE [NSBundle bundleForClass:TEST_CLASS]
    #define APP_NAME @"Tests"
    #else
    #define BUNDLE [NSBundle mainBundle]
    #define APP_NAME [[BUNDLE infoDictionary] objectForKey:(NSString *)kCFBundleNameKey]
    #endif
    

これにより、BUNDLEを使用することができます。つまり、[NSBundle mainBundle]を意味し、テストを実行するときにも機能します。

SenTestingKitをTests-Prefix.pchにインポートすると、SenTestingKitフレームワークのコンパイルも高速になり、すべてのテストファイルの先頭から#import <SenTestingKit/SenTestingKit.h>を省略できるようになります。

24
ma11hew28

プリプロセッサマクロは機能しません。実行時に環境を確認する必要があります。

Objective-c

static BOOL isRunningTests(void)
{
    NSDictionary* environment = [[NSProcessInfo processInfo] environment];
    return (environment[@"XCTestConfigurationFilePath"] != nil);
}

Swift

var unitTesting : Bool 
{
    return ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil
}

(Xcode 11用に更新)

31
Robert

新しいビルド構成を追加することを検討してください。

Xcode 4では、左側のナビゲーターでプロジェクトをクリックします。

メインウィンドウでプロジェクトをクリックし、[情報]タブを選択します。

「+」ボタンをクリックして、新しい構成を追加します(必要に応じて「test」と呼ぶことができます)。

次に、ターゲットをクリックして、ビルド設定タブに移動します。

「プリプロセッサマクロ」を検索

ここでは、新しいビルド構成にプリプロセッサマクロを追加できます。

新しい「テスト」構成をダブルクリックして、TESTING = 1を追加します。

最後に、ビルドスキームを編集します。スキームのテストオプションを選択します。 「ビルド構成」ドロップダウンメニューがあるはずです。 「テスト」構成を選択します。

29
David

Robertが提案したisRunningTests()の提案を使用する代わりに、コード自体に環境変数のチェックを追加することにしました。

  1. 現在のスキームを編集(プロダクト/スキーム/スキームの編集)またはCommand + <
  2. テスト構成をクリックします
  3. 引数をクリックして、「実行アクションの引数と環境変数を使用する」のチェックを外します
  4. 「環境変数」セクションを展開し、変数TESTINGに値YESを追加します
  5. これをコードのどこかに追加し、必要なときにいつでも呼び出します。
 + (BOOL) isTesting
    {
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        return [environment objectForKey:@"TESTING"] != nil;
    }

完了すると、画面は次のようになります。

The screen should look like this

上記のコードは、テストモードまたはアプリケーションモードで実行しているときにTESTING環境変数を検索します。このコードは、単体テストファイルではなく、アプリケーションに組み込まれます。使用できます

#ifdef DEBUG
...
#endif

本番環境でコードが実行されるのを防ぐため。

16
focused4success

Swift 3.0でのロバートの答え:

func isRunningTests() -> Bool {
    let environment = ProcessInfo().environment
    return (environment["XCInjectBundleInto"] != nil);
}
5
Houman

テストビルド構成を作成し、ターゲットの「Other Swift Flags」プロパティを「-DTEST」に設定すると、Swiftコード。アプリのSwiftコードで使用できるように、アプリターゲットのビルド設定で設定してください。

Other Swift Flags setting for DEBUG and TEST

次に、このセットを使用して、次のようにコードをテストできます。

func testMacro() {
   #if !TEST 
       // skipping over this block of code for unit tests
   #endif
}
3
ucangetit

私はそのような長い時間をテストし、結果を見つけました:

Preproessorマクロを単体テストターゲットに追加するだけでなく(多くのメソッドを使用できます 単体テストの変数のみを使用 、@ MattDiPasqualeメソッドに従います)、

ただし、条件ターゲットファイルをテストターゲットに追加する必要もあります。このファイルの新しいプリプロセッサマクロがあるので、このファイルを再コンパイルする必要がありますが、このファイルは、プリプロセッサマクロが設定されなかったときにアプリケーションターゲットに組み込まれています。

これがお役に立てば幸いです。

2
regrecall

Xcode10用に更新:

static let isRunningUnitTests: Bool = {
    let environment = ProcessInfo().environment
    return (environment["XCTestConfigurationFilePath"] != nil)
}()
2
raf

IOSでは[UIApplication sharedApplication]は、単体テストの実行中にnilを返します。

0
Frank Schmitt

環境変数を調べて、単体テストが実行されているかどうかを確認します。ロバートの答えに似ていますが、パフォーマンスを確認するために1回だけチェックします。

+ (BOOL)isRunningTests {
   static BOOL runningTests;
   static dispatch_once_t onceToken;

   // Only check once
   dispatch_once(&onceToken, ^{
      NSDictionary* environment = [[NSProcessInfo processInfo] environment];
      NSString* injectBundle = environment[@"XCInjectBundle"];
      NSString* pathExtension = [injectBundle pathExtension];
      runningTests = ([pathExtension isEqualToString:@"octest"] ||
                      [pathExtension isEqualToString:@"xctest"]);
   });
   return runningTests;
}
0
kev

Xcode 8.3.2で動作するKevの回答の修正版

+(BOOL)isUnitTest {

    static BOOL runningTests;
    static dispatch_once_t onceToken;

    // Only check once
    dispatch_once(&onceToken, ^{
        NSDictionary* environment = [[NSProcessInfo processInfo] environment];
        if (environment[@"XCTestConfigurationFilePath"] != nil && ((NSString *)environment[@"XCTestConfigurationFilePath"]).length > 0) {
            runningTests = true;
        } else {
            runningTests = false;
        }
    });
    return runningTests;
}
0
Fresh One