単体テストを実行しているときに、一部のコードをスキップしたい(たとえば、[[UIApplication sharedApplication] openURL:..]
を実行したくない)。現在ユニットテストを実行しているかどうかのランタイムチェックを探しています。
単体テストが実行されている場合にObjective-Cランタイムをチェックするコードを見たことがありますが、それを見つけることができなくなりました。
このメソッド from google-toolbox-for-mac を使用できます
// Returns YES if we are currently being unittested.
+ (BOOL)areWeBeingUnitTested {
BOOL answer = NO;
Class testProbeClass;
#if GTM_USING_XCTEST // you may need to change this to reflect which framework are you using
testProbeClass = NSClassFromString(@"XCTestProbe");
#else
testProbeClass = NSClassFromString(@"SenTestProbe");
#endif
if (testProbeClass != Nil) {
// Doing this little dance so we don't actually have to link
// SenTestingKit in
SEL selector = NSSelectorFromString(@"isTesting");
NSMethodSignature *sig = [testProbeClass methodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:sig];
[invocation setSelector:selector];
[invocation invokeWithTarget:testProbeClass];
[invocation getReturnValue:&answer];
}
return answer;
}
NSClassFromString
とNSInvocation
が使用される理由は、xctestまたはocunitにリンクせずにコードをコンパイルできるようにするためです。
むしろ、「私はテストしていますか?」本番コード全体の条件文で、チェックを1つの場所(main
)に分離します。そこで、テスト用にalternateアプリケーションデリゲートをチェックします。利用可能な場合は、通常のアプリケーションデリゲートの代わりに使用します。これにより、通常の起動シーケンスが完全にバイパスされます。
int main(int argc, char *argv[])
{
@autoreleasepool {
Class appDelegateClass = NSClassFromString(@"TestingAppDelegate");
if (!appDelegateClass)
appDelegateClass = [AppDelegate class];
return UIApplicationMain(argc, argv, nil, NSStringFromClass(appDelegateClass));
}
}
この手法の詳細については、こちらをご覧ください: iOSアプリのデリゲートをテスト用に簡単に切り替える方法
プロジェクトを選択してから、テストターゲットを選択します。
[ビルド設定]を選択し、[すべて]と[結合]を選択します。検索ボックスに「preproc」と入力します。プリプロセッサマクロを探しています。
TEST
という名前のマクロをデバッグ構成に追加し、それを1
と等しく設定します。
次に、コードでこれを行うことができます。
#ifndef TEST
[[UIApplication sharedApplication] doEvilThingForTesting];
#endif
または、テスト環境で実行したいコードがある場合のみ:
#ifdef TEST
[[UIApplication sharedApplication] doAwesomeTestOnlyThing];
#endif
正確にはruntimeではありませんが、単体テスターはテストIIRCを実行する前にコードをコンパイルするため、同じ効果が得られるはずです。基本的に、テストを実行する直前にコードを変更します。
Xcode7.3についてはこのように確認できると思います
-(BOOL) isRunningUnitTests
{
NSDictionary* environment = [ [ NSProcessInfo processInfo ] environment ];
NSString* theTestConfigPath = environment[ @"XCTestConfigurationFilePath" ];
return theTestConfigPath != nil;
}
確認する最も簡単な(そしてXcode 7でXCTestを使用して作業する)方法は、一致するxctest
バンドルのプロセス情報を確認することです。
static BOOL isRunningTests(void)
{
NSDictionary* environment = [[NSProcessInfo processInfo] environment];
NSString* injectBundle = environment[@"XCInjectBundle"];
return [[injectBundle pathExtension] isEqualToString:@"xctest"];
}
ソース: https://www.objc.io/issues/1-view-controllers/testing-view-controllers/#integration-with-xcode
これを使用するだけです:
+ (BOOL)isUnitTestRunning
{
Class testProbeClass;
testProbeClass = NSClassFromString(@"XCTestProbe");
return (testProbeClass != nil);
}