XCTest 失败并出现异常“非 UI 客户端无法自动暂停”

Posted

技术标签:

【中文标题】XCTest 失败并出现异常“非 UI 客户端无法自动暂停”【英文标题】:XCTest fails with with exception 'Non-UI clients cannont be autopaused' 【发布时间】:2015-07-30 16:46:31 【问题描述】:

我正在尝试将 CLLocationManager 创建为具有默认参数的单音:

+ (GeolocationService *)defaultGeolocationService

    static GeolocationService *_defaultGeolocationService = nil;

    static dispatch_once_t oncePredicate;

    dispatch_once(&oncePredicate, ^
        _defaultGeolocationService = [[GeolocationService alloc] init];
        [_defaultGeolocationService initLocationManager];
    );

    return _defaultGeolocationService;


- (void)initLocationManager

    self.locationManager = [CLLocationManager new];
    self.locationManager.delegate = self;
    self.locationManager.pausesLocationUpdatesAutomatically = YES;
    [self.locationManager requestAlwaysAuthorization];

测试如下:

- (void)testInitWithDefaultsSettings

    GeolocationService *defaultGeolocationService = [GeolocationService defaultGeolocationService];

    XCTAssertTrue(defaultGeolocationService.settings.autoPause, @"autoPause");

我得到一个例外: *** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“非 UI 客户端无法自动暂停”

我应该怎么做才能使这个测试工作?

【问题讨论】:

我猜苹果不会对自己的代码进行单元测试。 :( 或者拼写检查,想想看。 【参考方案1】:

问题在于以下行

self.locationManager.pausesLocationUpdatesAutomatically = YES;

无法在未运行 UI 的应用程序上设置此属性(不知道为什么,我找不到任何有关它的文档)。

在初始化GeoLocationService 和设置self.locationManager.pausesLocationUpdatesAutomatically 之前,您可能需要在测试中进行一些检查以确保UI 已加载。

【讨论】:

另外,self.locationManager.allowsBackgroundLocationUpdates 会导致错误提示 Invalid parameter not satisfying: !stayUp || CLClientIsBackgroundable(internal->fClient) || _CFMZEnabled() (NSInternalInconsistencyException). 这是可以理解的,因为这些是与 UI 设备关联的属性。【参考方案2】:

我搜索了一些简单快速的解决方案来避免它,我找到了一些解决这个问题的方法我认为你有三个解决方案:

- 简单的:

为测试目标创建一个预处理器宏。但这取决于你有多少宏,如果你滥用它可能会使代码管理复杂化。

- 中一:

您知道所有单元测试都在模拟器上运行,所以为什么不尝试一下

#if !(TARGET_IPHONE_SIMULATOR)

但是您会告诉我,您也希望在模拟器上运行应用程序,如果您只这样做,您将无法在模拟器中的应用程序启动案例中使用该属性。

那么为什么不添加一个关于了解 XPCServiceName 正在运行的补充测试,如下所示:

NSString *serviceName = [NSProcessInfo processInfo].environment[@"XPC_SERVICE_NAME"];
BOOL amITesting = ([serviceName rangeOfString:@"xctest"].location != NSNotFound);

所以使用 #if !(TARGET_IPHONE_SIMULATOR) && !amITesting 你可以使用你的

self.locationManager.pausesLocationUpdatesAutomatically = YES;

测试会通过。

- 第三个:

我不喜欢这个解决方案,但我也写了它,这是猴子解决方案...如果您不想添加预处理器宏,请添加 try catch 并且测试也会通过。但我不建议你使用那个。

我希望它会有所帮助。

【讨论】:

【参考方案3】:

这是对单元测试和其他非 UI 进程的限制,原因只有 Apple 知道。这是我正在使用的解决方案:

let serviceName = ProcessInfo.processInfo.environment["XPC_SERVICE_NAME"]
let testing = serviceName?.hasSuffix("xctest") ?? false

if !testing 
    locationManager.pausesLocationUpdatesAutomatically = true

【讨论】:

以上是关于XCTest 失败并出现异常“非 UI 客户端无法自动暂停”的主要内容,如果未能解决你的问题,请参考以下文章

快速使用 XCTest 时不会出现编译错误

Objective-C 协议在 XCTest 中选择器失败,但在应用程序中失败 [重复]

XCTest 显示已删除测试的结果

XCTest - 等待谓词失败

Cordova + XCTest 导致“架构 i386 的未定义符号”

XCTest:由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'参数'测试“不能为零”。