Build Status CocoaPod Version

重要提示!即使 KIF 用于测试你的 UI,你也需要将其添加到你的单元测试目标,而不是你的 UI 测试目标。KIF 的神奇之处在于,它允许你从单元测试驱动你的 UI,并获得进程内测试的所有优势。

KIF iOS 集成测试框架

KIF,代表 Keep It Functional,是一个 iOS 集成测试框架。 它允许通过利用操作系统为视觉障碍人士提供的辅助功能属性,轻松实现 iOS 应用程序的自动化。

KIF 使用标准的 XCTest 测试目标构建并执行测试。 测试在主线程中同步进行(运行 run loop 以强制时间推移),从而允许更复杂的逻辑和组合。 这也允许 KIF 利用 Xcode 测试导航器、命令行构建工具和 Bot 测试报告。

KIF 使用未公开的 Apple API。 大多数 iOS 测试框架都是如此,并且对于测试目的是安全的,但重要的是 KIF 不要进入生产代码,因为它会导致你的应用程序提交被 Apple 拒绝。 请按照以下说明操作,以确保 KIF 已为你的项目正确配置。

如果需要支持更早的版本,请使用 v3.7.9更早的版本。目前活跃支持 Xcode 11.6 和 iOS 11-13。

特性

最小化间接性

KIF 的所有测试都用 Objective-C 编写。 这样可以最大限度地与你的代码集成,同时最大限度地减少你需要构建的层数。

易于配置

KIF 直接集成到你的 Xcode 项目中,因此无需运行额外的 Web 服务器或安装任何其他软件包。

广泛的操作系统和 Xcode 覆盖范围

KIF 的测试套件正在 iOS 8+ 和 Xcode 7+ 上运行。 较低版本可能仍然有效,但结果可能会有所不同。 我们会尽最大努力保持向后兼容性。

像用户一样测试

KIF 尝试模仿实际用户输入。 尽可能使用点击事件完成自动化。

与 Xcode 测试工具自动集成

你可以使用测试导航器轻松运行单个 KIF 测试,或使用 Bots 启动夜间验收测试。

查看 KIF 的实际应用

KIF 使用以下描述的技术来验证其内部功能。 只需使用 ⌘U 构建并测试 KIF 方案,即可看到一个测试套件,该套件可以执行其全部功能。 查看 “Tests” 组中的测试,了解如何构建自己的测试。

安装(使用 CocoaPods)

CocoaPods 是设置 KIF 的最简单方法。

你首先要做的是设置一个将用于 KIF 的测试目标。 如果你选择自动创建单元测试,你可能已经有一个名为 MyApplication_Tests 的目标。 如果你这样做了,如果你不将其用于单元测试,则可以继续使用它。 否则,请按照以下说明创建新的目标。

在 Xcode 中选择你的项目,然后单击编辑器左下角的 “Add Target”。 选择 iOS -> Test -> iOS Unit Testing Bundle。 给它一个产品名称,例如 “Acceptance Tests”、“UI Tests” 或其他指示你的测试过程意图的名称。

测试目标将添加一个头文件和实现文件,可能为 “Acceptance_Tests.m/h”,以匹配你的目标名称。 删除这些文件。

设置测试目标后,将以下内容添加到你的 Podfile 文件。 使用你的目标的名称(如果适用)。

target 'Your Apps' do
  ...
end

target 'Acceptance Tests' do
  pod 'KIF', :configurations => ['Debug']
end

运行 pod install 后,完成下面最终测试目标配置中的任务,以获取有关运行测试的最终详细信息。

安装(来自 GitHub)

要安装 KIF,你需要将 libKIF 静态库直接链接到你的应用程序中。 从 kif-framework/KIF 下载源代码,然后按照以下说明进行操作。 屏幕截图来自 Yosemite 上的 Xcode 6,但这些说明对于任何操作系统版本上的 Xcode 5 或更高版本都应相同。

我们将使用一个简单的项目作为示例,你可以在此存储库的 Documentation/Examples/Testable Swift 中找到它。

Simple App

将 KIF 添加到你的项目文件

第一步是将 KIF 项目添加到现有应用程序的 ./Frameworks/KIF 子目录中。 如果你的项目使用 Git 进行版本控制,则可以使用子模块来简化将来的更新

cd /path/to/MyApplicationSource
mkdir Frameworks
git submodule add https://github.com/kif-framework/KIF.git Frameworks/KIF

如果你不使用 Git,只需下载源代码并将其复制到 ./Frameworks/KIF 目录中。

将 KIF 添加到你的工作区

通过将 KIF 项目与你的主项目一起添加到工作区中,让你的项目了解 KIF。 在 Finder 中找到 KIF.xcodeproj 文件,然后将其拖到项目导航器 (⌘1) 中。

Added KIF to the project

创建测试目标

你需要为你的应用程序创建一个测试目标。 如果你在创建项目时选择自动创建单元测试,则你可能已经有一个名为 MyApplicationTests 的目标。 如果你这样做了,如果你不将其用于单元测试,则可以继续使用它。 否则,请按照以下说明创建新的目标。

在 Xcode 中选择你的项目,然后单击编辑器左下角的 “Add Target”。 选择 iOS -> Test -> iOS Unit Testing Bundle。 给它一个产品名称,例如 “Acceptance Tests”、“UI Tests” 或其他指示你的测试过程意图的名称。

测试目标将添加一个头文件和实现文件,可能为 “Acceptance_Tests.m/h”,以匹配你的目标名称。 删除这些文件。

配置测试目标

现在你已经有了测试目标,将测试添加到该目标。 在项目导航器中仍然选择项目设置,并在项目设置中选择新的集成测试目标,然后选择 “Build Phases” 选项卡。 在 “Link Binary With Libraries” 部分下,点击 “+” 按钮。 在出现的工作表中,选择 “libKIF.a” 并单击 “Add”。 为 CoreGraphics.framework 和 QuartzCore.framework 重复该过程。

KIF 需要 IOKit.framework,但它并不与其他系统框架位于同一位置。 要链接到它,请将 “-framework IOKit” 添加到 “Other Linker Flags” 构建设置。

Add libKIF library screen shot

Add libKIF library screen shot

KIF 利用 Objective C 的能力来在对象上添加类别,但默认情况下,静态库未启用此功能。 要启用此功能,请将 -ObjC 标志添加到你的测试捆绑包目标上的 “Other Linker Flags” 构建设置中,如下所示。

Add category linker flags screen shot

阅读下面的 最终测试目标配置 以获取有关运行测试的最终详细信息。

安装辅助功能标识符测试

通常,你通过其辅助功能标签来识别 UI 元素,以便 KIF 尽可能接近地模拟真实用户的交互。 但是,在某些情况下,你可能必须使用辅助功能标识符,这些标识符不会暴露给用户。 如果使用 CocoaPods,请通过 Identifier CocoaPods 子规范安装其他基于标识符的测试

pod 'KIF/IdentifierTests'

如果不使用 CocoaPods,则可以通过包含 "KIFUITestActor-IdentifierTests.h" 来添加基于标识符的测试。

最终测试目标配置

你需要你的测试在你的应用程序中运行。 Xcode 在创建新的测试捆绑包目标时默认情况下会为你执行此操作,但如果你要迁移旧的捆绑包,请按照以下步骤操作。

首先,通过选择 “Build Phases”,展开 “Target Dependencies” 部分,单击 “+” 按钮,然后在出现的新工作表中选择你的应用程序目标并单击 “Add”,来添加你的应用程序。

接下来,配置你的捆绑包加载器。 在 “Build Settings” 中,展开 “Linking” 并将 “Bundle Loader” 编辑为 $(TEST_HOST)。 展开 “Testing” 部分,并将 “Test Host” 编辑为 $(BUILT_PRODUCTS_DIR)/MyApplication.app/MyApplication,其中 MyApplication 是你的应用程序的名称。 还要确保 “Wrapper Extension” 设置为 xctest

最后一步是配置单元测试,以便在你触发测试 (⌘U) 时运行。 单击你的方案名称,然后选择 “Edit Scheme…”。 单击侧栏中的 “Test”,然后单击左下角的 “+”。 选择你的测试目标,然后单击 “OK”。

示例测试用例

配置你的项目以使用 KIF 后,就可以开始编写测试了。 KIF 测试中使用了两个主要类:测试用例 (KIFTestCase, XCTestCase 的子类) 和 UI 测试参与者 (KIFUITestActor)。 XCTest 测试运行程序加载测试用例类并执行其测试。 在这些测试中,测试者执行通常模仿用户交互的 UI 操作。 三个最常见的测试者操作是 “点击此视图”、“在此视图中输入文本” 和 “等待此视图”。 这些步骤作为 KIFUITestActor 上的工厂方法包含在基本 KIF 实现中。

KIF 依赖于 iOS 的内置辅助功能来执行其测试步骤。 因此,你的应用程序必须完全可访问。 这也是确保每个人都可以使用你的应用程序的好方法。 在使你的应用程序可访问时,为你的视图提供合理的标签通常是一个不错的起点。 更多详细信息可在 Apple 的文档 中找到。

第一步是创建一个测试类来测试某些功能。 在我们的例子中,我们将创建一个登录测试 (LoginTests)。 创建一个从 KIFTestCase 继承的新类。 你可能必须更新导入以指向 <KIF/KIF.h>。 测试方法名称提供了一个唯一的标识符。 你的 KIFTestCase 子类应如下所示

LoginTestCase.h

#import <KIF/KIF.h>

@interface LoginTests : KIFTestCase
@end

LoginTestCase.m

#import "LoginTests.h"
#import "KIFUITestActor+EXAdditions.h"

@implementation LoginTests

- (void)beforeEach
{
    [tester navigateToLoginPage];
}

- (void)afterEach
{
    [tester returnToLoggedOutHomeScreen];
}

- (void)testSuccessfulLogin
{
    [tester enterText:@"user@example.com" intoViewWithAccessibilityLabel:@"Login User Name"];
    [tester enterText:@"thisismypassword" intoViewWithAccessibilityLabel:@"Login Password"];
    [tester tapViewWithAccessibilityLabel:@"Log In"];

    // Verify that the login succeeded
    [tester waitForTappableViewWithAccessibilityLabel:@"Welcome"];
}

@end

测试中的大多数测试者操作已经由 KIF 框架定义,但 -navigateToLoginPage-returnToLoggedOutHomeScreen 不是。 这些是特定于你的应用程序的自定义操作的示例。 添加此类步骤很容易,并且使用 KIFUITestActor 类别中的工厂方法完成,类似于我们添加场景的方式。

KIFUITestActor+EXAdditions.h

#import <KIF/KIF.h>

@interface KIFUITestActor (EXAdditions)

- (void)navigateToLoginPage;
- (void)returnToLoggedOutHomeScreen;

@end

KIFUITestActor+EXAdditions.m

#import "KIFUITestActor+EXAdditions.h"

@implementation KIFUITestActor (EXAdditions)

- (void)navigateToLoginPage
{
    [self tapViewWithAccessibilityLabel:@"Login/Sign Up"];
    [self tapViewWithAccessibilityLabel:@"Skip this ad"];
}

- (void)returnToLoggedOutHomeScreen
{
    [self tapViewWithAccessibilityLabel:@"Logout"];
    [self tapViewWithAccessibilityLabel:@"Logout"]; // Dismiss alert.
}

@end

现在应该配置所有内容。 当你使用测试按钮、⌘U 或 Xcode 测试导航器 (⌘5) 运行集成测试时。

与其他测试框架一起使用

运行测试不需要 KIFTestCase。 测试可以直接在 XCTestCase 或任何子类中运行。 基本要求是,当你调用 testersystem 时,self 必须是 XCTestCase 的实例,并且你必须在 setUp 中调用 KIFEnableAccessibility

例如,以下 Specta 测试无需对 KIF 或 Specta 进行任何更改即可工作

#import <Specta.h>
#import <KIF.h>

SpecBegin(App)

describe(@"Tab controller", ^{

  it(@"should show second view when I tap on the second tab", ^{
    [tester tapViewWithAccessibilityLabel:@"Second" traits:UIAccessibilityTraitButton];
    [tester waitForViewWithAccessibilityLabel:@"Second View"];
  });

});

SpecEnd

如果要将 KIF 与不继承 XCTestCase 的测试运行程序一起使用,则你的运行程序类只需要实现 KIFTestActorDelegate 协议,该协议包含两个必需的方法。

在第一种情况下,测试运行程序应记录异常,如果 stopYES,则停止测试执行。 在第二种情况下,运行程序应记录所有异常,如果 stopYES,则停止测试执行。 这些异常利用 KIF 对 NSException 的扩展,其中包括异常的 userData 中的 lineNumberfilename 以记录错误的来源。

与 Swift 一起使用

由于在同一个项目中可以很容易地组合 Swift 和 Objective-C 代码,因此 KIF 完全能够测试用 Objective-C 和 Swift 编写的应用程序。

如果您想用 Swift 编写测试用例,则需要牢记两件事。

  1. 您的测试包的桥接头文件需要 #import <KIF/KIF.h>,因为 KIF 是一个静态库而不是一个头文件。
  2. testersystem 关键字是 C 预处理器宏,在 Swift 中不可用。 您可以轻松编写一个小的 XCTestCase 或任何其他类的扩展来访问它们。
extension XCTestCase {
    func tester(file : String = #file, _ line : Int = #line) -> KIFUITestActor {
        return KIFUITestActor(inFile: file, atLine: line, delegate: self)
    }

    func system(file : String = #file, _ line : Int = #line) -> KIFSystemTestActor {
        return KIFSystemTestActor(inFile: file, atLine: line, delegate: self)
    }
}

extension KIFTestActor {
    func tester(file : String = #file, _ line : Int = #line) -> KIFUITestActor {
        return KIFUITestActor(inFile: file, atLine: line, delegate: self)
    }

    func system(file : String = #file, _ line : Int = #line) -> KIFSystemTestActor {
        return KIFSystemTestActor(inFile: file, atLine: line, delegate: self)
    }
}

请参阅 Documentation/Examples/Testable Swift 以获取示例代码。

问题排查

模拟器启动但应用程序未出现,步骤在 10 秒后超时

当 XCTest 没有有效的测试主机时,会发生此问题。 请重新阅读上面关于“Bundle Loader”和“Test Host”设置的说明。 您可能错过了一些东西。

步骤失败,因为找不到视图

如果 KIF 无法找到视图,最可能的原因是该视图未设置其辅助功能标签。 如果视图是在 xib 中定义的,则可以使用检查器设置标签。 如果它是以编程方式创建的,只需将 accessibilityLabel 属性设置为所需的标签即可。

如果标签确实已正确设置,请仔细查看 KIF 给出的错误。 此错误应该更具体地告诉您为什么无法访问该视图。 如果您正在使用 -waitForTappableViewWithAccessibilityLabel:,请确保该视图实际上是可点击的。 对于标签等无法成为第一响应者的项目,您可能需要改用 -waitForViewWithAccessibilityLabel:

首次尝试运行时出现无法识别的选择器

如果您第一次尝试运行 KIF 时收到以下错误

2011-06-13 13:54:53.295 Testable (Integration Tests)[12385:207] -[NSFileManager createUserDirectory:]: unrecognized selector sent to instance 0x4e02830
2011-06-13 13:54:53.298 Testable (Integration Tests)[12385:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSFileManager createUserDirectory:]: unrecognized selector sent to instance 0x4e02830'

或者如果您在 KIF 代码中收到另一个“unrecognized selector”错误,请确保您已按照上述说明正确设置 -ObjC 标志。 没有此标志,您的应用程序将无法访问 KIF 正常工作所需的类别方法。

持续集成

强烈建议使用持续集成 (CI) 流程,它对于确保您的应用程序保持功能正常非常有用。 最简单的方法是使用 Xcode,无论是使用 Bots,还是使用 Jenkins 或其他使用 xcodebuild 的工具。 对于使用 xcodebuild 的工具,请查看 manpage 以获取有关使用测试目标的说明。

贡献

我们很高兴您对 KIF 感兴趣,并且我们很乐意看到您将它用于什么。

任何对 master KIF 存储库的贡献者都必须签署个人贡献者许可协议 (CLA)。 这是一个简短的表格,涵盖了我们的基本信息,并确保您有资格做出贡献。

当您有想要在 master 存储库中看到的更改时,发送一个 pull request。 在我们合并您的请求之前,我们会确保您在已签署 CLA 的人员列表中。

谢谢,祝您测试愉快!