【问题标题】:xcode 5 XCTestCase running not how i expectxcode 5 XCTestCase 运行不符合我的预期
【发布时间】:2013-10-01 07:12:17
【问题描述】:

在单元测试用例中,我尝试为我的应用程序创建一些自己的逻辑,例如从当前的另一个用户名注册或连接到不同的服务器,而不重复现有代码。 我尝试做的第一步是创建 XCTestCase、alloc 类,它支持外部连接并尝试从他那里获得委托调用。 但是 NSURLConnection 只是等待没有网络交换,所以我没有成功。

我尝试做的下一个案例是等待应用程序完成并执行所有问题:

- (BOOL)waitForCompletion:(NSTimeInterval)timeInterval {

NSDate *timeoutDate =
[NSDate dateWithTimeIntervalSinceNow:timeInterval];

do {

    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                             beforeDate:timeoutDate];

    if([timeoutDate timeIntervalSinceNow] < 0.0) {

        break;
    }

} while (self.hasOperationFinishedPerforming == NO);

return self.hasOperationFinishedPerforming;
}

但在这种情况下,应用程序启动,执行所有当前周期,但我不知道如何从当前应用程序代码中检测到正在运行的单元测试。我试图在单元测试目标上设置预处理器宏,但它不会影响应用程序内的代码,也只会影响测试类的代码。

有什么想法吗?

【问题讨论】:

  • 我也尝试设置预处理器宏,但也没有看到它们设置。也许这与以下事实有关:当您运行 xctests 时,xcode 正在运行您的应用程序并在 appDidFinishLaunching 之后将测试作为包注入。

标签: iphone xcode unit-testing xctest


【解决方案1】:

当您尝试测试实现委托的NSURLConnection 时,您需要注意正确实现与运行循环相关的代码。

您的waitForCompletion: 方法可能不起作用或不可靠。原因是,方法runMode:beforeDate: 直到在模式:NSDefaultRunLoopMode 中执行了“事件”之后才会返回 - 或者超时到期。一个事件源自某个“运行循环源”,最终成为一个被调用的方法。例如,NSURLConnection 就是这样一个“运行循环源”,因为它调度委托方法,这些委托方法是“事件”,最终由指定模式的目标运行循环执行。

现在,您循环到self.hasOperationFinishedPerforming == NO。该标志可能最终被设置,您可能期望运行循环将返回并检查该标志。但是,直到某些任意事件被安排到具有指定模式的运行循环之后,情况才会如此。只有这样(除非过期),runMode:beforeDate: 才会返回并最终检查标志。

为了使运行循环立即返回,您可以在您的完成处理程序中发送一个虚拟事件,或者在发出异步完成信号时发送到任何适当的位置: p>

    self.hasOperationFinishedPerforming == YES;
    [@"" performSelector:@selector(self) onThread:thread 
              withObject:nil 
           waitUntilDone:NO];

然而,这确实需要完成处理程序知道它将在测试环境中执行。

有一些解决方案可以完全避免这种情况,但需要第三方库。

【讨论】:

    【解决方案2】:

    假设您已将单元测试目标的 Bundle Loader 构建设置设置为使用您的应用,您可以确定您的应用是否作为单元测试的一部分运行,如下所示:

    静态 BOOL isRunningTests(void) { NSDictionary* 环境 = [[NSProcessInfo processInfo] 环境]; NSString* injectBundle = environment[@"XCInjectBundle"]; 返回 [[injectBundle pathExtension] isEqualToString:@"octest"]; // 对于 SenTestKit;对 XCTest 使用“xctest” } - (BOOL)应用程序:(UIApplication *)应用程序 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if (isRunningTests()) 返回是; // 这里是正常的应用程序启动内容... ... }

    话虽如此,您的单元测试不应测试任何依赖于可用的外部服务(如 API 或数据库)的东西。如果您无法避免使用这些类型的东西,那么您应该查看“模拟”对象(使用像 OCMock 这样的第 3 方库),它可以让您提取复杂的类并控制它们在您的测试环境中返回的内容。

    单元测试的目的不是测试其他人的 API 或数据库或 SDK,而是测试您的代码和算法。如果您无法以这种方式测试您的代码,这可能是您需要将代码重构为更多可测试块的信号。

    Graham Lee 有一本名为 "Test-Driven iOS Development" 的好书,我强烈推荐这本书讨论了如何为 iOS 项目编写单元测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 2020-07-10
      • 2020-10-29
      • 2013-10-18
      • 2011-04-28
      • 1970-01-01
      • 2017-01-27
      相关资源
      最近更新 更多