重要提示!即使KIF用于测试您的UI,您也需要将其添加到单元测试目标中,而不是UI测试目标中。KIF的神奇之处在于它允许您从单元测试中驱动UI,并享受所有进程测试的优势。
KIF iOS集成测试框架
KIF(Keep It Functional的缩写)是一个iOS集成测试框架,通过利用操作系统为有视觉障碍的人提供的可访问性属性,可以轻松自动化iOS应用程序。
KIF使用标准XCTest
测试目标构建和执行测试。测试在主线程中同步进行(运行运行循环以强制时间流逝),允许更复杂的逻辑和组合。这也允许KIF利用Xcode测试导航器、命令行构建工具和Bot测试报告。
KIF使用未经记录的Apple API。这对于大多数iOS测试框架都是真实的,但在测试目的下是安全的。但重要的是,KIF不要出现在生产代码中,因为这会导致您的应用程序提交被苹果公司拒绝。按照以下说明确保KIF正确配置您的项目。
支持Xcode 11.6和iOS 11-13,如果需要支持更早版本,请使用v3.7.9或更早的发行版。
特点
减少间接调用
所有KIF测试都是用Objective-C编写的。这允许您的代码实现最大程度的集成,同时最小化构建的层。
配置简单
KIF可以直接集成到您的Xcode项目中,因此无需运行额外的Web服务器或安装任何额外的包。
广泛的操作系统和Xcode覆盖
KIF的测试套件正在针对iOS 8+和Xcode 7+运行。较低版本可能仍然可行,但性能可能会有所不同。我们会尽最大努力保留尽可能多的向后兼容性。
像用户一样测试
KIF试图模拟实际用户输入。自动化会在可能的情况下使用触摸事件。
与Xcode测试工具的自动集成
您可以使用Test Navigator轻松运行单个KIF测试,或使用Bots启动夜间验收测试。
看看KIF的实际应用
KIF使用以下描述的技术来验证其内部功能。您可以通过构建和测试KIF方案(使用⌘U)来查看一个测试套件,它测试了其全部功能。查看“KIF Tests”组中的测试,以获得如何构建您自己的测试的想法。
使用CocoaPods安装
CocoaPods是与KIF设置的最简单方法。
首先,您需要为KIF设置一个测试目标。如果您在自动创建单元测试时选择了名为MyApplication_Tests的目标,您可能已经有了。如果您有,并且不打算用它来写单元测试,您可以继续使用它。否则,请按照以下说明创建一个新目标。
在Xcode中选择您的项目,然后点击编辑器左下角的“添加目标”。选择iOS -> 测试 -> iOS 单元测试_bundle。给它一个产品名称,如“验收测试”、“UI测试”或能表明测试过程意图的名称。
测试目标将添加一个头文件和实现文件,可能是与目标名称匹配的“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,但对于任何OS版本上的Xcode 5或更高版本,说明应相同。
我们将使用一个简单的项目作为示例,您可以在本存储库的Documentation/Examples/Testable Swift
中找到它。
将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)中。
创建测试目标
您需要为您的应用创建一个测试目标。如果您在创建项目时选择了自动创建单元测试,可能会已经有一个名为MyApplicationTests的测试目标。如果有的话,如果您没有使用它进行单元测试,您可以使用它。否则,按照以下说明创建一个新的。
在Xcode中选择您的项目,然后点击编辑器左下角的“添加目标”。选择iOS -> 测试 -> iOS 单元测试_bundle。给它一个产品名称,如“验收测试”、“UI测试”或能表明测试过程意图的名称。
测试目标将添加一个头文件和实现文件,可能是与目标名称匹配的“Acceptance_Tests.m/h”。删除这些文件。
配置测试目标
现在您有一个测试目标了,将测试添加到该目标中。在项目设置中保留项目导航器选择,并选择项目设置中的新集成测试目标,选择“构建阶段”标签。在“链接二进制与库”部分中,点击“+”按钮。在出现的表格中,选择“libKIF.a”并点击“添加”。重复该过程为CoreGraphics.framework和QuartzCore.framework。
KIF需要IOKit.framework,但它并不位于其他系统框架中。要链接它,将“-framework IOKit”添加到“其他链接器标志”的构建设置中。
KIF利用Objective-C在对象上添加分类的能力,但默认情况下这并不应用于静态库。要启用此功能,将-ObjC
标志添加到您的测试包目标的“其他链接器标志”构建设置中,如下所示。
阅读下文的“最终测试目标配置”以获得运行测试的最终细节。
安装可访问性标识符测试
通常情况下,您通过UI元素的访问性标签来识别UI元素,这样KIF可以尽可能真实地模拟用户的交互。然而,在某些情况下,您可能需要使用可访问性标识符,这些标识符不会暴露给用户。如果使用CocoaPods,通过Identifier CocoaPods subspec安装基于标识符的KIF测试。
pod 'KIF/IdentifierTests'
如果不使用 CocoaPods,可以通过包含 "KIFUITestActor-IdentifierTests.h" 来添加基于标识符的 KIF 测试。
最终测试目标配置
您需要确保测试在您的应用程序中运行。在创建新的测试束目标时,Xcode 默认会为您完成此操作,但如果您正在迁移旧束,请按照以下步骤操作。
首先,通过选择 "构建阶段",展开 "目标依赖" 部分,点击 "+" 按钮,然后在出现的新窗口中,选择您的应用程序目标并点击 "添加" 来添加您的应用程序。
接下来,配置您的束加载器。在 "构建设置" 中,展开 "链接" 并将 "Bundle Loader" 编辑为 $(TEST_HOST)
。展开 "测试" 部分,并将 "Test Host" 编辑为 $(BUILT_PRODUCTS_DIR)/MyApplication.app/MyApplication
(其中 MyApplication
是您的应用程序名称)。另外,请确保 "Wrapper Extension" 设置为 xctest
。
最后一步是配置您的单元测试,以便在触发测试时(⌘U)运行。点击您的方案名称,选择 "编辑方案..."。在侧边栏中点击 "测试",然后点击左下角的 "+"。选择您的测试目标并点击 "OK"。
示例测试用例
当您的项目配置为使用 KIF 后,是时候开始编写测试了。在 KIF 测试中有两个主要的类:测试用例(KIFTestCase
,是 XCTestCase
的子类)和 UI 测试演员(KIFUITestActor
)。XCTest 测试运行器加载测试用例类并执行它们的测试。在这些测试内部,测试者执行 UI 操作,通常模拟用户交互。最常用的三个测试者操作是 "点击此视图"、"在此视图中输入文本" 和 "等待此视图"。这些步骤包括在基础 KIF 实现中的 KIFUITestActor
上的工厂方法中。
KIF 依赖于 iOS 内置的无障碍功能来执行其测试步骤。因此,您的应用程序的无障碍功能是至关重要的。这也是确保您的应用程序可供每个人使用的好方法。给您的视图适当标签通常是使应用程序无障碍的一个好起点。更多详细信息可在 Apple 的文档 中找到。
首先步骤是创建一个用于测试某些功能的测试类。在我们的情况下,我们将创建一个登录测试(LoginTests
)。创建一个从 KIFTestCase 继承的新类。您可能需要更新导入以指向 <KIF/KIF.h>
。测试方法名称提供了一个唯一标识符。您的 KIFTestCase
子类应如下所示
LoginTestCase.h
#import <KIF/KIF.h>
@interface LoginTests : KIFTestCase
@end
登录测试用例.m
#import "LoginTests.h"
#import "KIFUITestActor+EXAdditions.h"
@implementation LoginTests
- (void)beforeEach
{
[tester navigateToLoginPage];
}
- (void)afterEach
{
[tester returnToLoggedOutHomeScreen];
}
- (void)testSuccessfulLogin
{
[tester enterText:@"[email protected]" 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
对于运行 KIF 测试不是必需的。测试可以直接在 XCTestCase
或任何子类中运行。基本要求是在您调用 tester
或 system
时,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
如果您想使用一个不继承自 XCTestCase
的测试运行器与 KIF 一起使用,您的运行器类只需要实现包含两个必要方法的 KIFTestActorDelegate
协议。
- (void)failWithException:(NSException *)exception stopTest:(BOOL)stop;
- (void)failWithExceptions:(NSArray *)exceptions stopTest:(BOOL)stop;
在第一种情况下,测试运行器应记录异常并在 stop
为 YES
时中止测试执行。在第二种情况下,运行器应记录所有异常,并在 stop
为 YES
时中止测试执行。异常利用了 KIF 对 NSException
的扩展,其中包含异常的 userData
中的 lineNumber
和 filename
,以记录错误的来源。
与 Swift 一起使用
由于在单个项目中很容易将 Swift 和 Objective-C 代码结合起来,KIF 完全能够在使用 Objective-C 和 Swift 编写的应用程序中测试。
如果您想使用 Swift 编写测试用例,请注意以下两点。
- 您的测试包的桥接头需要
#import <KIF/KIF.h>
,因为 KIF 是一个静态库而不是头文件。 tester
和system
关键字是 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)
}
}
请参阅文档/示例/Testable Swift以获取示例代码。
故障排除
模拟器启动但应用未出现,步骤10秒后超时
当 XCTest 没有有效的测试主机时,会出现此问题。重新阅读关于“包加载器”和“测试主机”设置的说明。你可能漏掉了某些内容。
步骤失败,因为没有找到视图
如果 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代码中遇到另一个"未识别的选择器"错误,请确保您已如上所述正确设置了-ObjC标志。没有此标志,您的应用程序无法访问KIF正确运行所需的类别方法。
持续集成
推荐使用持续集成(CI)过程,它对于确保您的应用程序始终保持功能非常重要。最简单的方法是使用Xcode,无论是使用机器、Jenkins还是其他使用xcodebuild的工具。对于使用xcodebuild的工具,请查看手册以了解如何使用测试目标。
贡献
我们很高兴你对KIF感兴趣,也很想看看它能带你去哪里。
要向KIF主仓库提交更改,您必须签署个人贡献者许可协议(CLA)。这是一份简短的形式,涵盖了我们的基本要求,并确保你有资格做出贡献。
当您希望在主仓库中看到更改时,请发送拉取请求。在我们合并您的请求之前,我们会确保您在已签署CLA的人名单中。
谢谢,祝您测试愉快!