以前すべてのテストケースの前後にあれこれするというのを書いたのですが、 最近のXCTestではXCTestObserverがdeprecatedとなっていて、いつ利用できなくなってもおかしくない状態になっていました。 最近これとはまた別の方法がわかったのでまとめます。

XCTestは内部にXCTestObservationCenterというプライベートクラスを持っていて、これがテストケースの実行を管理しているようです。 このクラスにアクセスできるようにするには以下のようなヘッダーをテストターゲットに追加します。

#import <Foundation/Foundation.h>
#import <XCTest/XCTest.h>

@protocol XCTestObservation <NSObject>

@optional
- (void)testCaseDidFail:(XCTestRun *)testRun withDescription:(NSString *)description inFile:(NSString *)file atLine:(unsigned long long)line;
- (void)testCaseDidStop:(XCTestRun *)testRun;
- (void)testCaseDidStart:(XCTestRun *)testRun;
- (void)testSuiteDidFail:(XCTestRun *)testRun withDescription:(NSString *)description inFile:(NSString *)file atLine:(unsigned long long)line;
- (void)testSuiteDidStop:(XCTestRun *)testRun;
- (void)testSuiteDidStart:(XCTestRun *)testRun;
- (void)stopObserving;
- (void)startObserving;

@end

@interface XCTestObservationCenter : NSObject

+ (id)sharedObservationCenter;
- (void)addTestObserverClass:(Class)observerClass;

@end

ヘッダーを見てわかるように、XCTestObservationCenterにObserverクラスを追加してやると、 すべてのテストケースの開始/終了がフックできるようになります。具体的には以下のようなクラスを実装します。

import Foundation
import XCTest

class TestObservationCenter: NSObject, XCTestObservation {
    override class func load() {
        let center = XCTestObservationCenter.sharedObservationCenter() as XCTestObservationCenter
        center.addTestObserverClass(self)
    }
    
    func testCaseDidStart(testRun: XCTestRun!) {
        // テストケースの開始時に呼ばれる
    }
    
    func testCaseDidStop(testRun: XCTestRun!) {
        // テストケースの終了時に呼ばれる
    }
}

この方法はプライベートAPIを利用しているので、今後使い続けられる保証はありません。

参考