View in English

  • 打开菜单 关闭菜单
  • Apple Developer
搜索
关闭搜索
  • Apple Developer
  • 新闻
  • 探索
  • 设计
  • 开发
  • 分发
  • 支持
  • 账户
在“”范围内搜索。

快捷链接

5 快捷链接

视频

打开菜单 关闭菜单
  • 专题
  • 相关主题
  • 所有视频
  • 关于

更多视频

大多数浏览器和
Developer App 均支持流媒体播放。

  • 简介
  • 转写文稿
  • 代码
  • 通过测试重复来诊断不可靠的代码

    测试重复可以帮助您调试最不可靠的代码。探索如何使用失败前的最大重复次数,并在测试计划、Xcode 和 xcodebuild 中借助失败测试模式,来追踪错误和崩溃因素,并使您的 app 对每个人都更稳定。为了能充分了解本节内容,我们建议熟悉 XCTest 并通过测试计划管理测试。更多信息,请查看 WWDC19 中的“在 Xcode 中测试”。

    资源

      • 高清视频
      • 标清视频

    相关视频

    WWDC22

    • 为 Xcode Cloud 创建快速而可靠的测试

    WWDC21

    • 探索数码旋钮、触控板和 iPad 指针自动化
    • 接受 XCTest 中的预期失败
    • 认识 Swift 中的 async/await
  • 搜索此视频…

    Hello and welcome to WWDC 2021. I'm Suzy, and I work on XCTest in Xcode. In this session, we're gonna learn about how to diagnose unreliable code with test repetitions, a tool to repeat your tests.

    In the process of running tests that exercise your app, your tests may occasionally fail when running unreliable code.

    You may run into this type of inconsistency when dealing with race conditions, environment assumptions, global state, or communication with external services. These are hard bugs to track down because they're challenging to reproduce. One way to diagnose these types of failures is to run your tests repeatedly. Test repetition, added in Xcode 13, allows you to repeat a test up to a specified number of iterations with a stopping condition. Xcode supports three test repetition modes. The first mode is Fixed iterations. Fixed iterations will repeat your tests a fixed number of times regardless of the status. Fixed iterations is great for understanding the reliability of your test suite and helping keep it reliable as new tests are introduced over time. The second is Until failure. Until failure will continue to repeat a test until it fails. I love using this tool to reproduce a nondeterministic test failure to catch it in the debugger. Lastly is Retry on failure. Retry on failure will retry your test until it succeeds up to a specified maximum. This is useful to identify unreliable tests which fail initially but eventually succeed on reattempt. If a test in CI is exhibiting this behavior, you could enable Retry on failure in your test plan temporarily and gather additional data to fix the issue. It's important to remember retrying failures can hide problems in the actual product. Some functionality fails initially before eventually succeeding, so it's best to use this mode temporarily to diagnose the failures. Let's get a better understanding of how this works in practice. I created an app called IceCreamTruckCountdown that tells me how long until the ice cream truck drives by my home. I love when the truck has cookies and cream, and so I wrote a test called testFlavors to ensure that the truck has all the flavors. testFlavors has a truck that I get from the truckDepot.

    I call prepareFlavors and, lastly, assert that the truck has all 33 flavors. Recently, I've noticed testFlavors sometimes fails on the main branch in Xcode Cloud. To gather more information, I temporarily configured my test plan, enabling Test Repetition Mode to Retry on failure. Let's take a look at the report navigator and check our cloud reports.

    My tests are inconsistently failing, so let's check this last one for more information.

    If I expand the first device open, there is an iteration label here letting us know it was the first iteration of this test.

    Huh. And when I expand all the other rows, the assertion failures are all the same, and this last test passed. I expected all the tests to pass consistently, not just on one device. I'm gonna try to reproduce this failure locally. Let's go to our file that has testFlavors.

    I'll Control-click on the test diamond for our test. In the menu, I'll select Run "testFlavors()" Repeatedly… to bring up the test repetition dialog. Here you can select the stopping condition of your repetitions, set Maximum Repetitions, and other options like Pause on Failure. I want to try to reproduce the issue that happened in our cloud report, so I'm setting my stopping condition to go through maximum repetitions and keep it at 100.

    Now I'll run my test.

    Oh, yay! The test failed locally. When I click on the failure annotation, it displays the same error that happened in Xcode Cloud, and it failed 4 out of 100 times. Great! I can now debug this issue. I'll Control-click again on the test diamond for testFlavors, selecting Run "testFlavors()" Repeatedly… but this time, I'm gonna use stop on failure so I can debug the issue when it happens. Thankfully, Xcode automatically selects Pause on Failure for me, so I can catch the error in the debugger.

    All right, we have caught the issue. And I know we're looking at inconsistencies with the flavors on the truck, so I'll take a look at our truck object in the debugger.

    It seems strange that flavors is 0 when it should be 33 because we already called prepareFlavors. I wonder if we've made it inside this completionHandler. I'll add a breakpoint and click Continue.

    Hmm, that seems wrong.

    Oh, the fulfill is called in the outer completionHandler and not the inner prepareFlavors completionHandler.

    This is a fairly simple bug caused by asynchronous events with multiple completionHandlers and the expectation not being fulfilled in the correct place. XCTest's support for Swift 5.5's async/await lets me simplify this test so it won't happen again. To transform this test to use async/await, I'll add “async throws” to the method header.

    I'll use the “await” version of getting the iceCreamTruck from the truckDepot.

    I'll use the "await" version of prepareFlavors.

    I'll keep the same assert, but the truck is no longer optional.

    Let's run this test one more time to make sure that it is fixed. I'll Control-click and select Run "testFlavors()" Repeatedly… and once again select Maximum Repetitions as the stop condition.

    Yay! The test passed 100 times. I'm now confident that this is fixed, and I'm ready to remove Retry on failure from the test plan and commit my change. So we just got a better understanding of how to use this at desk and one way to run your test repeatedly in CI by configuring it in your test plan. Let's talk about another way to run your tests with repetition, like in the demo, using the CLI. When running xcodebuild directly, you can add xcodebuild flags which override any test plan setting. Pass -test-iterations with a number to run a test a fixed number of times or combine it with -retry-tests-on-failure or -run-tests-until-failure to use it with one of the other stopping conditions. To run your test the same as in the demo with xcodebuild, you start with the base xcodebuild command used to run your tests and add the flags -test-iterations set to 100 and -run-tests-until-failure. In summary, use test repetitions as a tool to help diagnose unreliable code. For more information about handling inconsistent tests, watch "Embrace expected failures in XCTest." To learn more about Swift async, check out "Meet async/await in Swift." Thanks for watching. [percussive music]

    • 2:39 - testFlavors

      func testFlavors() {
          var truck: IceCreamTruck?
      
          let flavorsExpectation = XCTestExpectation(description: "Get ice cream truck's flavors")
          truckDepot.iceCreamTruck { newTruck in
              truck = newTruck
              newTruck.prepareFlavors { error in
                  XCTAssertNil(error)
              }
              flavorsExpectation.fulfill()
          }
      
          wait(for: [flavorsExpectation], timeout: 5)
          XCTAssertEqual(truck?.flavors, 33)
      }
    • 6:31 - testFlavors: add async throws to method header

      func testFlavors() async throws {
          var truck: IceCreamTruck?
      
          let flavorsExpectation = XCTestExpectation(description: "Get ice cream truck's flavors")
          truckDepot.iceCreamTruck { newTruck in
              truck = newTruck
              newTruck.prepareFlavors { error in
                  XCTAssertNil(error)
              }
              flavorsExpectation.fulfill()
          }
      
          wait(for: [flavorsExpectation], timeout: 5)
          XCTAssertEqual(truck?.flavors, 33)
      }
    • 6:32 - testFlavors: use the async version of the ice cream truck

      func testFlavors() async throws {
          let truck = await truckDepot.iceCreamTruck()
              truck = newTruck
              newTruck.prepareFlavors { error in
                  XCTAssertNil(error)
              }
              flavorsExpectation.fulfill()
          }
      
          wait(for: [flavorsExpectation], timeout: 5)
          XCTAssertEqual(truck?.flavors, 33)
      }
    • 6:33 - testFlavors: use the async version of prepareFlavors

      func testFlavors() async throws {
          let truck = await truckDepot.iceCreamTruck()
          try await truck.prepareFlavors()
          XCTAssertEqual(truck?.flavors, 33)
      }
    • 6:50 - testFlavors: the truck is no longer optional

      func testFlavors() async throws {
          let truck = await truckDepot.iceCreamTruck()
          try await truck.prepareFlavors()
          XCTAssertEqual(truck.flavors, 33)
      }

Developer Footer

  • 视频
  • WWDC21
  • 通过测试重复来诊断不可靠的代码
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载 (英文)
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • News Partner Program (英文)
    • Video Partner Program (英文)
    • 安全赏金计划 (英文)
    • Security Research Device Program (英文)
    打开菜单 关闭菜单
    • 与 Apple 会面交流
    • Apple Developer Center
    • App Store 大奖 (英文)
    • Apple 设计大奖
    • Apple Developer Academies (英文)
    • WWDC
    获取 Apple Developer App。
    版权所有 © 2025 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则