問題の概要
iOSのUI自動化テストにおいてWebDriverAgent (WDA) を実行する際、テストスイートの起動直後にプロセスがクラッシュし、テストが失敗する問題が発生する場合があります。これは特にXcode 11.4以降の環境でWDAの古いビルドを使用した場合に顕著に現れます。
エラーログの分析
テスト実行時のコンソール出力には、以下のような NSInvalidArgumentException のスタックトレースが記録されます。
Test Case '-[UITestingUITests testRunner]' started.
t = 0.00s Start Test
t = 0.01s Set Up
-[UITestingUITests internalImplementation]: unrecognized selector sent to instance 0x283250c30
t = 0.05s Assertion Failure: <unknown>:0: failed: caught "NSInvalidArgumentException", "-[UITestingUITests internalImplementation]: unrecognized selector sent to instance 0x283250c30"
(
0 CoreFoundation 0x000000019a21e9a4 <redacted> + 252
1 libobjc.A.dylib 0x00000001993f79f8 objc_exception_throw + 56
...
5 WebDriverAgentLib 0x0000000103019e0c -[FBFailureProofTestCase setUp] + 136
6 XCTest 0x0000000101136c88 __48-[XCTestCase _performSetUpSequenceWithSelector:]_block_invoke_2 + 492
...
)
Test Case '-[UITestingUITests testRunner]' failed (0.066 seconds).
ログの核心部分は unrecognized selector sent to instance であり、対象のインスタンスに対して internalImplementation というメソッド(セレクタ)が存在しないことを示しています。
原因
AppleはXcode 11.4のリリースにおいて、XCTestフレームワーク内部で利用されていたプライベートAPIである internalImplementation を完全に削除しました。WebDriverAgentのソースコード内では、テストの失敗を抑制するためのプロキシを設定する際にこのAPIを直接呼び出しているため、Xcode 11.4以降の環境ではセレクタ解決に失敗し、ランタイム例外がスローされます。
解決策
この問題を回避するには、WDAのソースコードを修正し、internalImplementation の存在を動的にチェックするフォールバック処理を追加する必要があります。
WebDriverAgentLib/Utilities/FBFailureProofTestCase.m ファイルを開き、対象のメソッド内にある以下のコードを探します。
修正前のコード
self.internalImplementation = (_XCTestCaseImplementation *)[FBXCTestCaseImplementationFailureHoldingProxy proxyWithXCTestCaseImplementation:self.internalImplementation];
修正後のコード
セレクタの応答を確認し、APIが存在しない場合は代替のフラグを設定するようにロジックを書き換えます。変数名と代入の構造を整理し、可読性と安全性を向上させます。
BOOL supportsInternalImpl = [self respondsToSelector:@selector(internalImplementation)];
if (supportsInternalImpl) {
_XCTestCaseImplementation *baseImplementation = self.internalImplementation;
id proxyInstance = [FBXCTestCaseImplementationFailureHoldingProxy proxyWithXCTestCaseImplementation:baseImplementation];
self.internalImplementation = (_XCTestCaseImplementation *)proxyInstance;
} else {
// Xcode 11.4以降では internalImplementation が削除されたため、フォールバック処理を行う
self.shouldHaltWhenReceivesControl = NO;
}
コードの修正が完了したら、WebDriverAgentプロジェクトをクリーンビルドし、再度ターゲットデバイスまたはシミュレータに対してテストランナーをデプロイします。これにより、XCTestの初期化シーケンス中に発生していた未認識セレクタの例外が抑制され、テストスイートが正常に実行されるようになります。