【发布时间】:2015-11-10 12:21:35
【问题描述】:
我有一个带有两个按钮的简单应用程序,它调用 JSON Web 服务并打印出结果消息。
我想尝试新的 XCode 7 UI 测试,但我不明白如何模拟 API 请求。
为简单起见,我构建了一个没有实际请求也没有任何异步操作的示例。
我在主目标中有ZZSomeAPI.swift 文件:
import Foundation
public class ZZSomeAPI: NSObject {
public class func call(parameter:String) -> Bool {
return true
}
}
然后我的ZZSomeClientViewController.swift:
import UIKit
class ZZSomeClientViewController: UIViewController {
@IBAction func buttonClick(sender: AnyObject) {
print(ZZSomeAPI.call("A"))
}
}
现在我添加了一个 UITest 目标,记录了点击按钮,我有类似的东西:
import XCTest
class ZZSomeClientUITests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
XCUIApplication().launch()
}
func testCall() {
let app = XCUIApplication()
app.childrenMatchingType(.Window).elementBoundByIndex(0).childrenMatchingType(.Other).element.childrenMatchingType(.Other).elementBoundByIndex(1).childrenMatchingType(.Button).elementBoundByIndex(0).tap()
}
}
所以这有效并且运行测试将打印出true。但是我想在 API 返回 false 时包含一个测试,而不会弄乱 API。因此,我将ZZSomeAPI.swift添加到 UI Tests 目标并尝试了方法调配(UITest 代码已更新):
import XCTest
class ZZSomeClientUITests: XCTestCase {
override func setUp() {
super.setUp()
continueAfterFailure = false
XCUIApplication().launch()
}
func testSwizzle() {
XCTAssert(ZZSomeAPI.call("a"))
XCTAssertFalse(ZZSomeAPI.callMock("a"))
XCTAssert(ZZSomeAPI.swizzleClass("call", withSelector: "callMock", forClass: ZZSomeAPI.self))
XCTAssertFalse(ZZSomeAPI.call("a"), "failed swizzle")
}
func testCall() {
XCTAssert(ZZSomeAPI.swizzleClass("call", withSelector: "callMock", forClass: ZZSomeAPI.self))
let app = XCUIApplication()
app.childrenMatchingType(.Window).elementBoundByIndex(0).childrenMatchingType(.Other).element.childrenMatchingType(.Other).elementBoundByIndex(1).childrenMatchingType(.Button).elementBoundByIndex(0).tap()
}
}
extension NSObject {
public class func swizzleClass(origSelector: String!, withSelector: String!, forClass:AnyClass!) -> Bool {
var originalMethod: Method?
var swizzledMethod: Method?
originalMethod = class_getClassMethod(forClass, Selector(origSelector))
swizzledMethod = class_getClassMethod(forClass, Selector(withSelector))
if (originalMethod == COpaquePointer(bitPattern: 0)) { return false }
if (swizzledMethod == COpaquePointer(bitPattern: 0)) { return false }
method_exchangeImplementations(originalMethod!, swizzledMethod!)
return true
}
}
extension ZZSomeAPI {
public class func callMock(parameter:String) -> Bool {
return false
}
}
所以,testSwizzle() 通过,这意味着 swizzling 有效。但是testCall() 仍然打印true 而不是false。
是不是因为只有在 UITest 和 main 目标是两个不同的应用程序时才在测试目标上进行调配?
有没有办法解决这个问题?
我找到了Mock API Requests Xcode 7 Swift Automated UI Testing,但我不确定如何在此处使用launchArguments。
在示例中只有一种情况,但我需要模拟 call() 方法以获得不同测试方法的不同结果......如果我使用 launchArgument 例如 MOCK_API_RESPONSE 包含要返回的完整响应,主要目标应用程序委托将有一些“丑陋的仅测试”代码......有没有办法检查(在主目标中)它正在为 UITest 目标编译,所以它只包含那个模拟launchArguments的代码?
最干净的选择确实是开始工作......
【问题讨论】:
标签: ios cocoa-touch xcode7 xcode-ui-testing