使用 KIF 进行功能测试:在我的视图控制器加载后调用 beforeEach?

Posted

技术标签:

【中文标题】使用 KIF 进行功能测试:在我的视图控制器加载后调用 beforeEach?【英文标题】:Feature tests with KIF: beforeEach is called after my view controller is loaded? 【发布时间】:2015-02-13 15:05:59 【问题描述】:

我有一个简单(我猜)的问题。

我想使用 Specta 和 KIF 在我的应用中进行功能测试。问题是我在 View Controller 的 viewDidLoad 方法中设置依赖关系,而在我的规范的 beforeEach 方法中,我正在注入假对象只是为了不访问网络。

结果错误,因为 viewDidLoad 在规范中的 beforeEach 方法之前被调用。

是否有可能在 AppDelegate 加载根视图控制器之前设置依赖关系,以便正确设置所有内容?

【问题讨论】:

【参考方案1】:

依赖于目标的测试(如 KIF 和某些单元测试)在应用启动后启动,所以不,如果没有一些可怕的骇客,你不能让 beforeEach 在你的 AppDelegate 之前运行。

我不知道您是如何进行依赖注入的,所以这是我们的做法/一些一般策略。

KIF 测试最好不要在代码级别模拟

这是因为 KIF 是 UIAutomation 的一种替代方案,主要用于 UI 级别的特性/功能测试。您并不想过多地更改您的应用程序代码。使用 OHHTTPStubs 之类的网络框架或 OCMock 之类的框架来最好地实现模拟,这些框架在仅限于单元测试时效果最佳。

如何在“真实”应用中模拟网络请求

这里最好的方法是使用 OHHTTPStubs 或 AMY 服务器(由制作 KIF 的同一个人制作)或 Nocilla 之类的东西来返回存根响应。这样您就可以让您的应用程序代码完全运行。例如 OHHTTPStubs 使用 NSURLProtocol 拦截您的请求,因此从应用程序的角度来看,它几乎与访问网络一样好。

我真的很想模拟出那些对象

如果你真的真的很想用不同的对象模拟依赖注入的对象,那么有一些越来越少的 hacky 选项。

1) 使用允许修补依赖项的真正 DI 框架(或构建您自己的框架)。我用过Typhoon,它是合理的。这里的标准想法是利用控制反转来发挥您的优势。由于您从应用程序上下文而不是直接获取所有对象,因此调整应用程序上下文抽象层要容易得多。 Typhoon 甚至有一个关于这个主题的 wiki 页面:https://github.com/appsquickly/Typhoon/wiki/Integration-Testing

2) 跟踪您要注入的对象的来源,并希望在源头进行模拟和更改。这不是最优雅的,无论如何你都在破解一个 DI 框架,但也许你没有足够的时间或复杂性来让切换到 DI 框架值得。

3) 一路破解到顶层。有一个测试 AppDelegate,它从您的普通 AppDelegate 子类化,并在 KIF 测试期间使用它(当然还有它存根或模拟出您想要的对象)。这并不灵活,但同样,也许您只需要一个测试用例或其他东西:

int main(int argc, char *argv[])

    int returnValue;
    @autoreleasepool 
        BOOL inIntegrationTests = NSClassFromString(@"KIFTestCase") != nil;
        if (inIntegrationTests) 
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegateForTest");
        
        else 
            returnValue = UIApplicationMain(argc, argv, nil, @"AppDelegate");
        
    
    return returnValue;

不幸的是,最终这不是一个简单的“我该把这个方法放在哪里”的问题。

【讨论】:

感谢您的广泛回答。我们必须模拟一些对象,因为我们希望在 Travis 上运行功能测试。除了将 HTTP 请求存根之外,我们还需要对其他事情做同样的事情,例如定位服务。我还悬赏this related question。 @MaciejGórski 我也回答了这个问题。给出了两种方法,因为我不确定位置服务的质量。如果是 CLLocationManager,那么第一个模式可以正常工作。如果它是其他带有单例的定位服务,那么您需要稍微花哨并使用第二种方法。我强烈建议使用 Typhoon 之类的东西,因为它非常适合这种情况(需要在集成测试期间模拟出来)。 @KonradSzczęśśniak 谢谢!很高兴我能帮上忙。 @plluke 这在 Xcode 7 beta 上也适用吗?我使用类似的东西进行单元测试,但是在 Xcode 7 beta 6 上找不到测试委托并且测试目标崩溃。 对不起,如果这不完全相关,但 plluke 的回答帮助我修复了我的 KIF 配置,所以我想我可以帮助别人。我在这里遇到了这个问题:***.com/questions/18538958/… 基本上 KIF 找不到应用程序的关键窗口(并因此引发了一个不太有用的异常)。如果您像上面的 plluke 那样根据测试环境交换 AppDelegate 实例,那么您可能会为 KIF 提供一个 AppDelegate 配置,但该配置不会创建正确的键窗口。

以上是关于使用 KIF 进行功能测试:在我的视图控制器加载后调用 beforeEach?的主要内容,如果未能解决你的问题,请参考以下文章

我们可以在 KIF 测试类中创建模型类的实例吗

构建失败:没有这样的模块“KIF”

在 KIF 测试步骤之间传递数据

使用 Kif 进行 Swift UI 测试

单击使用 KIF 的警报视图

KIF(保持功能性)区分 iPhone 和 iPad