如何将我的 App 模块导入 MyAppUITests 文件?
How to import my App module into MyAppUITests file?
这是我的简单测试用例:
import XCTest
@testable import MyApp //it doesn't work
因为这个:
class TabBarControllerTests: XCTestCase {
override func setUp() {
super.setUp()
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject([], forKey: DBTabBarOrderedIndexesKey) //key is undefined, because of lack of my app module
defaults.synchronize()
continueAfterFailure = false
XCUIApplication().launch()
}
func testIsOrderOfTabsSaved() {
XCUIApplication().tabBars.buttons["Catering"].tap()
//what next?
}
}
点击 UITabBarItem
后,我更改了 DBAppSettings.mode
的值,所以在这里我想访问我的 DBAppSettings.mode
属性 以检查它是否真的变了
我注意到有一件奇怪的事情,当我构建我的应用程序并检查构建的内容时,没有为我的 UITest 目标构建。重要吗?
这是 Apple 的回复:
UI tests execute differently from Unit tests - Unit tests run inside your application process so they can access your application code. UI tests execute in a separate process, outside your application, so they can simulate how the user interacts with the application. It’s not expected that you will be able to access your app class from a UI test.
由于 Apple 阻止您从 UI 测试访问您的主应用程序,您可能会考虑重新组织您的应用程序结构以存储需要检查到 UI 可以访问的位置的相关数据测试。
您可以考虑将定义和数据从您的主应用程序 class 移动到一个单独的 class,它可以由测试框架加载。
您需要在 UI 测试中访问的每个对象都必须是 UI 测试目标的一部分。这包括对象依赖性。这是一个湿滑的斜坡,而且是一团糟。
与其让你的测试知道你的应用程序,不如试着扭转它,让你的应用程序知道它正在接受测试。一种方法是使用 launchArguments
属性:
app = XCUIApplication()
app.launchArguments.append("TestMode")
app.launch()
然后在您的应用中:
if NSProcessInfo.processInfo().arguments.contains("TestMode") {
// I am running in test mode
}
在您的情况下,应用可以相应地设置 NSUserDefaults。
我通过将一些东西从我的应用程序目标中提取到两个框架(模型和视图模型)中来解决无法访问的符号问题,然后我可以将它们导入到我的 UI 测试中。
至于访问 executable 的实际内存,你不能,但你可以测试应该在该模式下某处出现在屏幕上的东西。我用这个断言来例如检查是否存在 table 视图单元格:
XCTAssertTrue(tables.cells.staticTexts["Cell title I expect to exist"].waitForExistence(timeout: 1))
由于您可以使用辅助功能,因此您可以通过这种方式访问相当多的内容。我想你可以添加一个不可见的标签,其中包含你的应用程序内存的转储 - 仅在测试模式下!
我也使用启动参数为 UI 测试配置我的应用程序,正如 Michael 所建议的:.
这是我的简单测试用例:
import XCTest
@testable import MyApp //it doesn't work
因为这个:
class TabBarControllerTests: XCTestCase {
override func setUp() {
super.setUp()
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject([], forKey: DBTabBarOrderedIndexesKey) //key is undefined, because of lack of my app module
defaults.synchronize()
continueAfterFailure = false
XCUIApplication().launch()
}
func testIsOrderOfTabsSaved() {
XCUIApplication().tabBars.buttons["Catering"].tap()
//what next?
}
}
点击 UITabBarItem
后,我更改了 DBAppSettings.mode
的值,所以在这里我想访问我的 DBAppSettings.mode
属性 以检查它是否真的变了
我注意到有一件奇怪的事情,当我构建我的应用程序并检查构建的内容时,没有为我的 UITest 目标构建。重要吗?
这是 Apple 的回复:
UI tests execute differently from Unit tests - Unit tests run inside your application process so they can access your application code. UI tests execute in a separate process, outside your application, so they can simulate how the user interacts with the application. It’s not expected that you will be able to access your app class from a UI test.
由于 Apple 阻止您从 UI 测试访问您的主应用程序,您可能会考虑重新组织您的应用程序结构以存储需要检查到 UI 可以访问的位置的相关数据测试。
您可以考虑将定义和数据从您的主应用程序 class 移动到一个单独的 class,它可以由测试框架加载。
您需要在 UI 测试中访问的每个对象都必须是 UI 测试目标的一部分。这包括对象依赖性。这是一个湿滑的斜坡,而且是一团糟。
与其让你的测试知道你的应用程序,不如试着扭转它,让你的应用程序知道它正在接受测试。一种方法是使用 launchArguments
属性:
app = XCUIApplication()
app.launchArguments.append("TestMode")
app.launch()
然后在您的应用中:
if NSProcessInfo.processInfo().arguments.contains("TestMode") {
// I am running in test mode
}
在您的情况下,应用可以相应地设置 NSUserDefaults。
我通过将一些东西从我的应用程序目标中提取到两个框架(模型和视图模型)中来解决无法访问的符号问题,然后我可以将它们导入到我的 UI 测试中。
至于访问 executable 的实际内存,你不能,但你可以测试应该在该模式下某处出现在屏幕上的东西。我用这个断言来例如检查是否存在 table 视图单元格:
XCTAssertTrue(tables.cells.staticTexts["Cell title I expect to exist"].waitForExistence(timeout: 1))
由于您可以使用辅助功能,因此您可以通过这种方式访问相当多的内容。我想你可以添加一个不可见的标签,其中包含你的应用程序内存的转储 - 仅在测试模式下!
我也使用启动参数为 UI 测试配置我的应用程序,正如 Michael 所建议的: