在 iOS 应用程序中测试学习身份验证

Testing Cognito Authentication in iOS App

我有一个 iOS 应用程序,其 Cognito 身份验证的实现非常类似于 CognitoYourUserPoolsSample. Most important fragments are in SignInViewController.swift:

  1. 当用户点击登录时,添加异步任务:

    var passwordAuthenticationCompletion: AWSTaskCompletionSource<AWSCognitoIdentityPasswordAuthenticationDetails>?
    ...
    @IBAction func signInPressed<...> {
        ...
        let authDetails = AWSCognitoIdentityPasswordAuthenticationDetails(username: self.username.text!, password: self.password.text! )
        self.passwordAuthenticationCompletion?.set(result: authDetails)
        ...
    
  2. 稍后我们得到成功或错误响应:

    extension SignInViewController: AWSCognitoIdentityPasswordAuthentication {
          public func getDetails<...> {
              DispatchQueue.main.async {
                  // do something in case of success
          ...
    
          public func didCompleteStepWithError<...> {
              DispatchQueue.main.async {
                 // do something in case of failure
          ...
    

我还有一个 UI 测试,填写用户名和密码,点击登录并验证响应:

class MyAppUITests: XCTestCase {
    ...
    func loginTest() {
        let usernameField = <...>
        usernameField.tap()
        usernameField.typeText("user@domain.com")
        ... 
        // same for password field
        // then click Sign In
        <...>.buttons["Sign In"].tap()

目前此测试针对实际 AWS 基础设施进行,由于多种原因,该基础设施并不理想。我想要的是 模拟来自 AWS 的各种响应。

我该怎么做?

我认为最好的办法是模拟或插入任务队列,但我不确定如何处理。任何方向将不胜感激。如果您以其他方式处理类似的任务,我也想听听您的想法,谢谢。

好吧,我不太熟悉 AWS iOS SDK 以及它是如何实现身份验证流程的,所以请对以下内容持保留态度。我希望这不是一个完整的答案,而是一个笼统的 "strategy"。我在我当前的项目中实现了类似的方法,不仅用于登录,而且实际上我建立的所有远程连接。

您需要做三件事:

  1. 运行 一个小型本地网络服务器 在您的 UI 测试目标 中。我在当前项目中使用 Embassy and Ambassador。将其配置为 return Cognito(或其他端点)通常给出的任何响应。我只是手动 curl 编辑了一个请求并将响应保存在某个地方,但在我的情况下,我收到了纯数据(而不是,例如,一个完整的登录页面显示在 web 视图中......)。我的猜测是 Cognito 实际上显示了一个登录(网络)视图,并且在成功登录时使用深度 link 到 "go back" 到您的应用程序,最终调用您的 AWSCognitoIdentityPasswordAuthentication 方法(成功或错误) .你可以有测试目标,即网络服务器直接调用深度 link 如果你知道它是什么样子(应该可以找出来?)。

  2. 添加一些机制来在测试期间切换 Cognito 端点。不幸的是,这需要添加生产代码,但如果做得好,应该不会太困难。我通过使用我在测试期间设置的启动环境变量来做到这一点(见下文)。除非您的网络服务器支持 https(Embassy 不是开箱即用的),否则这还需要以某种方式配置 App Transport Security。最困难的部分肯定是弄清楚端点在 SDK 中的哪个位置构造以及如何更改它。快速浏览 documentation 让我相信 webDomain 是保存它的地方,但我看不到它是如何设置的。 属性 甚至是只读的,这使事情变得复杂。不过,我假设您可以在项目的某些配置中更改它?否则它就像一个方法调配的案例......抱歉我不能在这里提供更多的声音方向。

  3. 在测试期间,确保将在相关应用程序流程期间访问的真实端点切换到 http://localhost/...。我这样做是通过使用 XCUIApplication().launchEnvironment["somekey"] = "TESTINGKEY",它与我在第二步中准备的生产代码相匹配。在我的例子中,我可以简单地加载不同的端点(它有本地主机域和其他与原始域相同的路径)。根据测试用例(成功登录、无效凭据等)配置您的网络服务器的响应。

我承认这 was/is 做了大量工作,但对我来说这是值得的,因为我可以轻松地 运行 整个应用程序流程(涉及大量传出请求)而无需任何网络使用权。无论如何,我必须自己实施我们的身份验证系统,这让我可以很好地控制使用哪些 URL 以及在哪里使用,从而可以很容易地在一个地方根据启动环境变量将它们存根。在我的案例中,最丑陋的部分实际上是仅在我的测试中启用 ATS 异常 ,出于各种原因我不得不使用 运行 脚本。