ユニットテストを使用して新しいプロジェクトを作成する場合、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はそれらを区別すべきではないと思いますか?
テストビルド構成を作成する代わりに、私は:
Tests-Prefix.pch
ファイルを作成しました:
#define TEST 1
#import <SenTestingKit/SenTestingKit.h>
#import "CocoaPlant-Prefix.pch"
testsターゲットのビルド設定のPrefixヘッダーフィールドにパスを入力しました。
作成した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>
を省略できるようになります。
プリプロセッサマクロは機能しません。実行時に環境を確認する必要があります。
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用に更新)
新しいビルド構成を追加することを検討してください。
Xcode 4では、左側のナビゲーターでプロジェクトをクリックします。
メインウィンドウでプロジェクトをクリックし、[情報]タブを選択します。
「+」ボタンをクリックして、新しい構成を追加します(必要に応じて「test」と呼ぶことができます)。
次に、ターゲットをクリックして、ビルド設定タブに移動します。
「プリプロセッサマクロ」を検索
ここでは、新しいビルド構成にプリプロセッサマクロを追加できます。
新しい「テスト」構成をダブルクリックして、TESTING = 1を追加します。
最後に、ビルドスキームを編集します。スキームのテストオプションを選択します。 「ビルド構成」ドロップダウンメニューがあるはずです。 「テスト」構成を選択します。
Robertが提案したisRunningTests()の提案を使用する代わりに、コード自体に環境変数のチェックを追加することにしました。
+ (BOOL) isTesting { NSDictionary* environment = [[NSProcessInfo processInfo] environment]; return [environment objectForKey:@"TESTING"] != nil; }
完了すると、画面は次のようになります。
上記のコードは、テストモードまたはアプリケーションモードで実行しているときにTESTING環境変数を検索します。このコードは、単体テストファイルではなく、アプリケーションに組み込まれます。使用できます
#ifdef DEBUG
...
#endif
本番環境でコードが実行されるのを防ぐため。
Swift 3.0でのロバートの答え:
func isRunningTests() -> Bool {
let environment = ProcessInfo().environment
return (environment["XCInjectBundleInto"] != nil);
}
私はそのような長い時間をテストし、結果を見つけました:
Preproessorマクロを単体テストターゲットに追加するだけでなく(多くのメソッドを使用できます 単体テストの変数のみを使用 、@ MattDiPasqualeメソッドに従います)、
ただし、条件ターゲットファイルをテストターゲットに追加する必要もあります。このファイルの新しいプリプロセッサマクロがあるので、このファイルを再コンパイルする必要がありますが、このファイルは、プリプロセッサマクロが設定されなかったときにアプリケーションターゲットに組み込まれています。
これがお役に立てば幸いです。
Xcode10用に更新:
static let isRunningUnitTests: Bool = {
let environment = ProcessInfo().environment
return (environment["XCTestConfigurationFilePath"] != nil)
}()
IOSでは[UIApplication sharedApplication]
は、単体テストの実行中にnil
を返します。
環境変数を調べて、単体テストが実行されているかどうかを確認します。ロバートの答えに似ていますが、パフォーマンスを確認するために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;
}
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;
}