是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?
Posted
技术标签:
【中文标题】是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?【英文标题】:Is it possible to stub HTTP requests in Xcode 7 automated UI tests? 【发布时间】:2015-09-28 16:22:14 【问题描述】:我一直在尝试使用 OHHTTPStubs 之类的工具在 Xcode 7 自动化 UI 测试中拦截和存根/模拟 HTTP 请求,但没有成功。
以下是我如何尝试在 UI 测试文件的 setUp 方法中使用 OHHTTPStubs 捕获任何 HTTP 请求的示例:
override func setUp()
super.setUp()
let matcher: OHHTTPStubsTestBlock = (request) -> Bool in
return true
OHHTTPStubs.stubRequestsPassingTest(matcher) (response) -> OHHTTPStubsResponse! in
return OHHTTPStubsResponse.init()
UI 测试的工作方式是否可以防止这种情况发生?有没有人能够做到这一点?
【问题讨论】:
嘿,你最终找到解决方案了吗? 是的,刚刚添加在下面。 要动态存根 HTTP 请求,您可以使用 SBTUITestTunnel,查看我的回答 here 【参考方案1】:正如 Martijn 正确指出的那样,由于 UI 测试的工作方式,您无法在运行时直接与应用程序交互,因此任何 HTTP 模拟或对 XCUITestCase
中的 NSUserDefaults
之类的操作都不会影响您的应用程序。
如果您确实需要能够模拟 HTTP 或设置和拆卸您的应用程序环境以进行特定的 UI 测试,您将需要在启动应用程序之前在 @987654325 的 setUp()
方法中设置启动参数或启动环境变量@ 然后修改您的应用代码以读取启动参数或环境变量并引导测试环境。
示例测试用例
class MyTestCase: XCTestCase
/**
Called before each test in this test case.
*/
override func setUp()
super.setUp()
let app = XCUIApplication()
app.launchArguments = [ "STUB_HTTP_ENDPOINTS" ]
app.launch()
AppDelegate 示例
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
#if DEBUG
if (NSProcessInfo.processInfo().arguments.contains("STUB_HTTP_ENDPOINTS"))
// setup HTTP stubs for tests
#endif
return true
注意:为了在本例中使用像 OHHTTPStubs
这样的 HTTP 模拟框架,您需要使用的存根代码和任何 JSON 固定装置都需要在您的应用目标中,而不是测试目标。
这是一个非常有用的话题:https://github.com/AliSoftware/OHHTTPStubs/issues/124
【讨论】:
听起来虽然这确实允许您实现存根,但您还将发布一个应用程序,其中包含存根“代码”和存根网络文件。这可能是一件非常糟糕的事情。 我将存根代码包装在对 DEBUG 预处理器宏的 if 检查中,因此存根代码实际上不应进入 App Store 构建。我已经更新了代码示例以显示这一点。感谢您指出这一点。【参考方案2】:UI 测试在与您的应用程序不同的实例中运行。虽然您可能可以使用应用程序中的类,但它们只是一个副本。
在您的应用程序中,您可以使用此处提供的解决方案检测您是否在 UI 测试模式下运行:How to detect if ios app is running in UI Testing mode
我个人选择了原帖中提到的launchEnvironment
解决方案;我的设置如下所示:
override func setUp()
super.setUp()
let app = XCUIApplication()
app.launchEnvironment["TEST"] = "1"
app.launch()
我的一个单例实例化器(称为 RealmManager
)看起来像这样(用于实例化 Realm 数据库):
func realm() -> Realm
let dic = NSProcessInfo.processInfo().environment
if dic["TEST"] != nil
return try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: "test"))
return try! Realm()
如果你不喜欢重复,但你可能已经在重复 XCUIApplication().launch()
,你总是可以创建一个扩展 XCTestCase
的自定义测试用例类,用这个添加覆盖 setUp,然后在你所有的测试类。
【讨论】:
如何执行不同的测试用例?例如,如果我想测试登录成功和登录失败,最好的做法是存根这两个不同的响应......你如何用你的逻辑处理这样的事情?我只能理解我是在“应用领域”还是“测试领域”中运行,但我无法处理不同的“测试领域”响应。 假用户? “用户”+“错误密码”=失败,“用户”+“密码”=成功。以上是关于是否可以在 Xcode 7 自动化 UI 测试中存根 HTTP 请求?的主要内容,如果未能解决你的问题,请参考以下文章
在 UI 测试期间,如何使用 Xcode 7 截取我的 UI 截图?