我正在构建一个iOS框架,用于收集有关iOS应用程序中各种事件的信息,并执行本地和远程分析。其中一些事件无法在应用程序之外进行测试:例如,查看控制器转换。为了测试这些事件,我构建了一个测试iOS应用程序,并希望使用Xcode UI测试:
启动视图控制器转换,例如,点击将VC推送到导航控制器的按钮,或切换到选项卡控制器中的其他选项卡
验证框架是否能够检测到视图控制器转换并生成必要的事件(例如,将它们发送到服务器)
问题是Xcode UI测试在应用程序外部运行,因此我无法访问任何共享对象来验证框架是否正常运行。我也无法插入任何模拟对象,因为我再也无法访问应用程序进程中加载的框架。
我尝试以某种测试模式加载框架并让它更新标签,其中包含一些UI测试可以读取的结果。但即使这样也很难,因为XCUIElement
没有给我实际的元素文本;我只能查询带有一些预定义文本的元素。我可以使用它,但对于一些应该相当微不足道的东西,它似乎是一种非常迂回的方法。
是否有更好的替代方法来测试只能在正在运行的应用中模拟的事件,然后验证我的框架是否能够检测并处理它们?除了查看控制器转换之外,我还对触摸交互,加速度计事件以及无法在应用程序外部模拟的其他功能感兴趣。当然,我可以模拟这些事件进行单元测试,但我还想自动测试,当这些事件发生在实际应用程序中时,我的框架中会生成正确的响应。
答案 0 :(得分:1)
您可以尝试使用SBTUITestTunnel。这个库扩展了UI测试的功能,添加了一些在像你这样的情况下可能派上用场的功能。
网络监控
该库允许您的测试目标收集在应用程序中调用的网络调用。用法很简单:
readline
网络监控的好处是所有测试代码和逻辑都包含在测试目标中。
自定义代码块
在其他用例中,您需要执行自定义代码才能在测试目标中方便地调用,您也可以这样做。
在应用目标
中注册代码块undef
并从测试目标
调用它func testThatNetworkAfterEvent() {
// Use SBTUITunneledApplication instead of XCUIApplication
let app = SBTUITunneledApplication()
app.launchTunnelWithOptions([SBTUITunneledApplicationLaunchOptionResetFilesystem]) {
// do additional setup before the app launches
// i.e. prepare stub request, start monitoring requests
}
app.monitorRequestsWithRegex("(.*)myserver(.*)") // monitor all requests containing myserver
// 1. Interact with UI tapping elements that generate your events
// 2. Wait for events to be sent. This could be determined from the UI (a UIActivitiIndicator somewhere in your app?) or ultimately if you have no other option with an NSThread.sleepfortimeinterval
// 3. Once ready flush calls and get the list of requests
let requests: [SBTMonitoredNetworkRequest] = app.monitoredRequestsFlushAll()
for request in requests {
let requestBody = request.request!.HTTPBody // HTTP Body in POST request?
let responseJSON = request.responseJSON
let requestTime = request.requestTime // How long did the request take?
}
}
目前,您只能从测试目标中注入数据 - >应用目标。如果您需要相反的方法,可以将该数据存储在NSUserDefaults中,并使用SBTUIApplication的 SBTUITestTunnelServer.registerCustomCommandNamed("myCustomCommandKey") {
injectedObject in
// this block will be invoked from app.performCustomCommandNamed()
return "any object you like"
}
方法获取它。
我个人不喜欢在您的应用程序目标中混合使用标准代码和测试代码,因此我建议仅在真正需要时才使用它。
修改强>
我已经更新了库并从愿景0.9.23开始,您现在可以将任何对象从块传递回测试目标。不再需要解决方法了!
答案 1 :(得分:0)
完成任务并不是一种自动化的方法,但确实使用断点作为中间方式,至少在您自动启动之前。您可以添加符号断点来点击UI方法,例如[UIWindow setRootViewController:],viewWillAppear等。
您可以明确定义模块,条件和操作,以便每当有人查看您的VC时,都会执行一些可能对您有所帮助的操作。
如果你可以在一些viewDidAppear上使用简单的“po myEvent”从你的框架中打印出一些东西,你就可以了。我从未尝试过使用更高级的方法作为动作,但也可以这样做。