View in English

  • Apple 开发者
    • 入门汇总

    探索“入门汇总”

    • 概览
    • 学习
    • Apple Developer Program

    及时了解最新动态

    • 最新动态
    • 开发者你好
    • 平台

    探索“平台”

    • Apple 平台
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    • App Store

    精选

    • 设计
    • 分发
    • 游戏
    • 配件
    • 网页
    • Home
    • CarPlay 车载
    • 技术

    探索“技术”

    • 概览
    • Xcode
    • Swift
    • SwiftUI

    精选

    • 辅助功能
    • App Intents
    • Apple 智能
    • 游戏
    • 机器学习与 AI
    • 安全性
    • Xcode Cloud
    • 社区

    探索“社区”

    • 概览
    • “与 Apple 会面交流”活动
    • 社区主导的活动
    • 开发者论坛
    • 开源

    精选

    • WWDC
    • Swift Student Challenge
    • 开发者故事
    • App Store 大奖
    • Apple 设计大奖
    • Apple Developer Centers
    • 文档

    探索“文档”

    • 文档库
    • 技术概述
    • 示例代码
    • 《人机界面指南》
    • 视频

    发布说明

    • 精选更新
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • Apple tvOS
    • Xcode
    • 下载

    探索“下载”

    • 所有下载
    • 操作系统
    • 应用程序
    • 设计资源

    精选

    • Xcode
    • TestFlight
    • 字体
    • SF Symbols
    • Icon Composer
    • 支持

    探索“支持”

    • 概览
    • 帮助指南
    • 开发者论坛
    • “反馈助理”
    • 联系我们

    精选

    • 《开发者账户帮助》
    • 《App 审核指南》
    • 《App Store Connect 帮助》
    • 即将实行的要求
    • 协议和准则
    • 系统状态
  • 快速链接

    • 活动
    • 新闻
    • 论坛
    • 示例代码
    • 视频
 

视频

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

更多视频

  • 简介
  • 概要
  • 转写文稿
  • 代码
  • 使用 AppIntentsTesting 验证你的 App Intents 采用情况

    AppIntentsTesting 是一个全新的框架,可通过 Siri、“快捷指令”和“聚焦”所使用的同款基础架构来验证你的 App Intents。探索如何执行意图、检查结果,并测试实体和查询——全程无需 UI 自动化。了解如何验证视图注释和“聚焦”索引等集成功能,助你在开发流程中尽早发现错误。

    章节

    • 0:16 - Introduction
    • 2:01 - Meet CometCal: your first test
    • 2:29 - How AppIntentsTesting works
    • 9:39 - Testing entity queries
    • 13:49 - Combining multiple intents
    • 16:27 - Test-only intents
    • 18:22 - Testing Spotlight indexing
    • 20:56 - Testing view annotations
    • 24:00 - The App Intents testing workflow
    • 25:19 - Next steps

    资源

    • Testing your App Intents code
    • App Intents Testing
      • 高清视频
      • 标清视频
  • 搜索此视频…

    大家好,我是 Venkatesh, App Intents 团队的一名软件工程师。 今天我将向您展示 如何测试您的 App Intents,

    使用全新的框架 AppIntentsTesting。 App Intents 框架是核心组成部分, 决定了您的应用 如何与系统集成。 每年,它为更多体验提供支持,例如, App Intents 让用户 能够通过 Siri 与应用互动。 它让用户能够使用 Shortcuts 应用 构建强大的自动化流程。

    Spotlight 使用它在全系统搜索中 呈现您应用的内容。 小组件使用它在主屏幕上 显示您的数据。

    如果您是 AppIntents 新手, 请查看 WWDC25 的这场讲座。 如果您想了解 最新进展, 请查看 WWDC26 的这场讲座。 由于 App Intents 驱动着如此多的体验, 每个 intent、entity 和 query 都必须正确运行。 AppIntentsTesting 是一个全新的框架, 让您能够测试这一切,以及更多内容。 以下是我们今天要介绍的内容。 首先,我将介绍示例应用, 并向您展示如何编写您的第一个测试。 接下来,我们将了解 AppIntentsTesting 如何运行测试。

    然后我们将进阶, 通过测试 entity 查询, 并组合多个 intent。

    最后, 我们将测试 App Intents 中的一些部分, 这些部分超出了您的应用范围: Spotlight 和视图注解。

    我现在直接进入正题, 向您展示这有多简单, 让您快速上手 AppIntentsTesting。

    这是 CometCal,一个示例日历应用。 这是一个 SwiftUI 应用, 管理日历、事件, 以及参与者,并且完全 集成了 App Intents。 我和同事 Justin 一直在开发这个应用, 以便让我们的太空 探险团队更轻松地管理任务。 在本节中, 我们将学习如何测试它, 使用 AppIntentsTesting。

    要了解我们如何让 CometCal 接入 Siri, 请查看他的代码实操。

    我先从编写一个简单的测试开始, 测试"创建日历"流程。

    开始使用 AppIntentsTesting 所需的一切, 只是一个 UI Testing bundle。 我还没有, 所以让我创建一个。

    让我给它起一个描述性的名称。 接下来,选择一个开发团队。 AppIntentsTesting 要求 测试运行器和应用 使用相同的开发团队 进行代码签名, 所以我需要确保 在此处选择正确的 Team。 接下来,我填入一个 Bundle Identifier。

    然后选择正确的 Target。 点击 Finish。

    这会为我创建 UI 测试 bundle。 让我为所有与 intent 执行相关的测试 创建一个新文件。

    很好,我现在已经准备好 开始编写一些测试了。

    让我导航到我正在测试的 intent。

    CreateCalendar 用指定的名称 和颜色创建一个新日历。

    首先,我需要导入 AppIntentsTesting 框架。

    我从标准的 XCTestCase 开始, 并创建一个测试方法。

    我通过创建一个 IntentDefinitions 对象来启动测试流程。

    IntentDefinitions 接收 CometCal 的 bundle identifier, 让我能访问应用定义的 每一个 intent、entity, 以及 query, 而无需导入该应用。 要访问某个特定 intent 的定义, 我可以使用 intents 属性, 并将 Intent 名称作为下标传入。

    这会返回一个 IntentDefinition 对象。 我可以在其上调用 makeIntent, 以创建一个填充好的 Intent 实例。

    我可以传入 intent 期望的任何参数。

    这里,CreateCalendarIntent 接收一个名称和一个颜色。 我负责一个对人类至关重要的 任务, 我需要一个描述性名称, 以便我和团队能完成这个任务。

    我将它命名为"占领土星"。 并给它一个颜色。 我将它设为红色。

    这里,color 是一个 AppEnum。 我只需传入 AppEnum 的原始字符串值, 框架会将其转换为正确的类型。 测试代码不针对 您的应用进行构建, 因此参数名称和类型 不提供自动补全。 我需要确保根据 intent 参数 正确填写它们。 这种类型转换对大多数参数类型 开箱即用。 但是,如果您想 传入自定义类型, 请在文档中查阅 IntentValueConvertibleWrapper。 现在我创建了 intent, 我调用 .run() 方法 在应用中执行它。

    如果我需要 intent 的 perform 方法 的返回值, 我可以获取 run 方法的结果, 并使用 value 属性来获取它。

    这里,CreateCalendarIntent 将 新日历作为 CalendarEntity 返回。

    这就是 CalendarEntity。

    它有一个 title 属性,我们可以检查它。

    所以,如果我想断言 新事件具有正确的标题,

    我首先使用 result.value 访问新日历, 然后简单地链式调用 所需的属性名称。 这使用动态成员查找 从新日历中获取标题。

    我现在准备好运行这个测试了。 但在此之前, 让我切换到手机, 查看一下我目前 有哪些日历。

    该应用目前有三个日历: 深空、任务控制中心 和观星。 运行测试后, 我期望"占领土星"日历 被添加到列表中。

    让我切换回 Xcode, 并运行这个测试。

    测试成功了。

    让我查看手机,确认 新日历是否存在。 是的,测试创建了 "占领土星"日历, 颜色为红色。

    只需五行代码, 我就通过测试在设备上 执行了一个 App Intent。 现在您已经看到 AppIntentsTesting 的实际效果, 我将更详细地介绍它。

    AppIntentsTesting 是一个针对 App Intents 的集成测试框架。 与 UI 测试类似, 它使用字符串来查找您的 intent, 而无需访问应用的内部实现。

    您的测试存放在 标准的 XCUITest bundle 中, 运行在自己的进程里。 您的应用在独立进程中运行, 并在设备上执行 AppIntents。

    测试运行器跨进程边界 执行您的 App Intents, 并接收执行结果, 而不共享任何状态。

    以下是 AppIntentsTesting 对开发者意味着什么。 您的测试贯穿完整的 App Intents 技术栈, 与用户使用的代码路径相同。 没有 mock,没有 stub。

    创建一个 XCUITest bundle, 或将其添加到现有的 XCUI 测试中。 您的持续集成 流水线会自动捕获它。 以任意方式组织您的应用代码。 您的测试 target 不会 从应用中导入任何代码—— 您只需传入一个 bundle identifier。

    这意味着您无需将应用代码 编译到测试 target 中。

    这一切为您提供了 跨版本稳定的测试。 它们不依赖任何 UI, 无论是您应用的还是系统的。

    有了这个概述, 我将继续进行一些更复杂的测试。 您应用的操作、数据和查询

    是您 App Intents 集成的基础构建块。 它们驱动着 Shortcuts、 Siri 交互和 Spotlight 搜索。 当这些代码出现回归时, 往往会导致 用户遇到 意外的系统行为。

    每当您的 entity 被查找时—— 在 Shortcuts 中,通过 Siri, 或者任何 App Intents 呈现它们的地方—— 您的 entity 查询负责 返回正确的结果。 AppIntentsTesting 帮助您验证 字符串查询的行为, 以及 identifier 查找 和建议的 entity。 以下是具体情况。 我有一个大体无害的设备, 叫做宇宙射线仪。 由于一次不幸的事故, 我需要将"宇宙射线校准"事件 重命名 为"宇宙射线重建"。 事实上,这种情况发生得太频繁了, 我或许应该为此创建一个 Shortcut。

    该事件已经存在于应用中。 于是我打开 Shortcuts 应用, 进入我的 Shortcut, 搜索该事件。

    最初,它显示了一个 建议事件的列表。 如果我想搜索 其他事件, 我可以使用搜索栏, 它会调用 EventEntity 的字符串查询 来确定结果。

    "没有可用选项"; 字符串查询尚未实现。 我将使用 AppIntentsTesting 以测试驱动的方式实现这个功能。

    这是我的测试。 我首先创建 entity 和 intent 定义。

    我希望确保应用 包含一组已知的事件, 所以我运行 SeedSampleEventsIntent。 这会重置应用数据并添加事件。 我稍后会回到这一点。 理想情况下,我会将 Entity 和 Intent 定义 从测试函数中提取出来, 以便其他测试可以复用, 并将数据填充 移到 setUp 方法中。 让我这样做。 从现在起, 我专注于纯粹的测试功能。

    这是更新后的测试。 我调用 Entity 字符串查询, 使用 Event entity 定义上的 entities(matching:) 方法。 这会在设备上执行字符串查询。 该方法返回一个 EventEntity 表示的数组, 因此您可以断言其数量。

    与 intent 类似, 我可以使用动态成员查找 来获取任何 entity 属性的值。 这里,我正在获取事件的标题, 并对其进行断言以确认 查询工作正常。 我来运行测试。 它失败了,正如预期。 失败信息告诉我 确切需要构建什么。

    现在我导航到 EventEntityQuery。 目前, 它可以通过 identifier 返回事件, 以及返回建议的事件。 但是,它没有 EntityStringQuery 功能。 让我添加一个。

    我将添加一个 EntityStringQuery 遵循,

    并实现 entities(matching:) 方法。 按标题过滤事件, 并返回匹配的 EventEntity。

    现在我回到测试并运行它, 它通过了。 我已确认 Entity 字符串查询按预期工作。

    现在,我在设备上验证更改。 首先,我确认事件存在。 接下来,我打开 Shortcuts 应用, 打开我的 Shortcut, 再次搜索相同的事件。 这次,它找到了该事件。

    我先编写了测试, 然后构建功能使其通过。 这就是使用 AppIntentsTesting 进行测试驱动开发。 现在,是时候重建宇宙射线仪了! 是时候进阶了, 在一个测试中组合多个 intent。

    通常,为了构建复杂的 Shortcut, 人们会获取一个 intent 的结果, 并将其作为参数传入另一个。 这种流程是 许多有用自动化的基础。

    以下是具体情况: 我为我的团队 设置了一个练习课程, 练习小行星躲避球。 但是,我们的一个队友是新人, 所以我最终把事件的目的 改为讲解规则。 由于这是应用的核心工作流, 我想编写一个测试来模拟它。

    这个测试建立在我们之前的示例上。 让我带您了解一下。

    首先运行带有所需参数的 CreateEventIntent。 我在之前的示例中介绍了 makeIntent 如何处理类型转换。

    前三个参数 都接受基本类型。

    最后一个更有趣。 calendar 参数 接受一个 CalendarEntity。 但是,我只是传入一个字符串。 AppIntents 运行时会自动 调用与 CalendarEntity 关联的 EntityStringQuery, 并填入第一个匹配值。

    创建事件后, 我检查标题以确认无误。

    接下来,我运行 UpdateEventIntent。 这接受一个事件, 以及我想要进行的任何更新。 由于我只是更新 标题,我传入该值。 对于要更新的事件, 我可以直接传入 原始 run 方法中的 EventEntity。 这反映了人们 在 Shortcuts 中组合 intent 的方式。

    最后,我断言事件 具有更新后的标题。

    这次,在测试设置期间, 我正在启动应用, 只是为了确认 它工作正常。 是时候运行测试了。 应用启动了,

    事件被创建了,

    然后被更新了。

    成功! Entity 创建、链式调用、 更新和断言, 全在设备上,在一个测试中完成。 现在,我把小行星躲避球的 规则手册放在哪里了…… AppIntentsTesting 测试轻量、 快速,可以在每次提交时运行。

    为了使测试结果可靠, 每个测试都需要自包含。 测试专用 intent 有助于实现这一点。

    测试专用 intent 简单、 专注,仅用于 辅助您的测试。 您可以使用它们 来改善测试功能。 您可以精确创建 测试所需的数据。 不会有之前运行遗留的数据 导致不稳定的结果。

    您可以直接跳转到应用中 的任何视图,无需 UI 导航。 如果您重新设计了某个页面, 这些测试仍然有效。 这里还有一个更宏观的思路: 测试专用 intent 可以封装 应用中的任何功能, 即使是您尚未 采用 App Intents 的部分。 内部导航、数据管理、 状态操控——将其封装在 测试专用 intent 中, 您就可以通过 AppIntentsTesting 进行测试。 CometCal 的源代码包含 许多测试专用 intent。 一个例子是来自早前字符串查询测试的 SeedSampleEventsIntent。 它在您的日历中 创建一组已知的事件。 以下是如何将任何 intent 设为测试专用 intent 的方法。

    用 isDiscoverable: false 标记它。 这可以防止系统 在其他地方暴露它。

    并将其包裹在 #if DEBUG 编译器指令中, 这样只有您的测试 才能访问此 intent。

    到目前为止,您已学会 如何独立测试您的 App Intents。 真正的强大之处在于, App Intents 如何让 您的功能跨系统 触达用户, 使他们能够在应用之外 使用应用的功能。 我现在将向您展示如何测试 这些系统级集成。

    Spotlight 让用户能够 从一个地方搜索整个系统。 当您索引您的 entity 时, 它们会直接出现在这些结果中, 让人们无需先打开应用 就能找到应用的内容。 当 CometCal 创建事件时, 它应该在 Spotlight 中索引该 entity。 然而,我曾经收到一条紧急消息, 来自我的舰队指挥官, 询问暗物质研讨会是什么时候。

    我知道纳秒都是宝贵的, 所以我想用 Spotlight 来获取这些信息, 并立即回复。 然而,Spotlight 搜索 什么也没找到。 这些关于暗物质的信息 确实很有趣, 但不是我要找的! 我去看了应用, 该事件确实存在。 我迅速把详情发给了他们, 然后开始调试。

    我导航到事件 创建代码进行调试。 这个 bug 很简单:在开发过程中, 我注释掉了索引代码, 却从未重新启用它。 应用的行为没有改变, 所以这个 bug 一直未被发现。

    修复也很简单, 只需取消注释索引调用。

    但如何确保 这种情况不再发生? 我可以编写一个测试,不是为了发现这个 bug, 而是为了防止回归。

    我首先使用 spotlightQuery() 方法 与 Spotlight 通信。 该方法接受一个字符串, 并返回一个 Spotlight 索引的 EventEntity 表示列表,包含匹配内容。 最初,该事件不存在, 所以我确认 spotlightQuery() 不返回任何结果。

    接下来,我使用 CreateEventIntent 创建一个事件, 与之前完全相同。

    创建后,我期望该事件 存在于 Spotlight 索引中, 所以我再次查询它。 我断言恰好有一个结果, 且标题匹配。 现在我运行测试…… 它通过了。 这个测试现在可以在每次提交时运行。 因此,如果 Spotlight 集成 再次出现问题, 这个测试会立即捕获到。

    现在,快速检查一下,确认 事件确实已在 Spotlight 中被索引。 太好了! 现在,我的舰队指挥官 可以以 Spotlight 的速度获得答案!

    视图注解告诉系统 您的视图当前显示的是哪个 entity, 这样 Siri 就能理解 屏幕上的内容并直接对其采取操作。 CometCal 每次导航到 事件时,都会告诉 Siri 屏幕上显示的是哪个 EventEntity。 所以,如果我正在查看一个事件, 而一个意外的虫洞跳跃 从我手中夺走了手机, 我总是可以呼叫说: "Siri,这个事件是什么时候?"

    理想情况下,视图注解告诉 Siri 屏幕上确切是哪个事件, Siri 立即作出回答。 但如果该注解损坏了, Siri 就完全不知道屏幕上是什么。

    现在,跨维度旅行 发生在我身上的频率比我承认的要高, 所以我真的需要这个功能正常工作。 让我借助 AppIntentsTesting 修复这个 bug。

    我首先通过 OpenEventIntent 导航到 某个事件的事件页面。

    因为这个测试存在于 一个 XCUITest bundle 中, 我可以使用 XCUI 自动化 来确认应用 确实在屏幕上渲染了 正确的事件。

    然后,我可以调用 Event entity 上的 viewAnnotations() 方法。 该方法检索 系统报告为当前显示在屏幕上的 EventEntity 视图注解列表。

    现在进行断言。 首先,由于屏幕上只有一个事件, 我断言系统只返回 一个 ViewAnnotation 对象。

    然后我断言 Event entity 根据标题是正确的。

    ViewAnnotation 对象 有一个 entity 属性, 存储着实际的 entity 表示。 因此,我可以使用动态成员查找 来断言特定属性, 例如标题。 现在我运行测试。 它失败了。

    然后,我导航到 EventDetailView 以查找原因。 问题出在 EntityIdentifier 上。 我不小心将事件的 日历 id 作为 identifier 传入了。

    修复很简单: 我将其改为事件的 id。

    现在我重新运行测试。 这次它通过了。

    所以,下次跨维度旅行 让我措手不及时, 我可以说"Siri,这个事件是什么时候?",

    并获得正确的回应。 我甚至可以追问"在哪里?",

    Siri 会回应位置信息。

    今天我介绍了很多内容。 现在,让我们退一步, 看看 AppIntentsTesting 如何增强您的 App Intents 开发工作流程。

    通过实现基础类型来 开启您的 AppIntents 之旅。 这些是您应用的 操作、数据和查询。 现在有了 AppIntentsTesting,您可以 验证这些类型的基础行为。

    这些测试充当您 App Intents 集成的单元测试。

    一旦基础经过测试, 就将您的应用 与系统进行更深入的集成。 为您的视图添加 entity 注解, 向 Spotlight 捐赠,并在应用间传递数据。 AppIntentsTesting 也让您 涵盖这些集成, 验证应用的各种体验, 覆盖用户使用应用的多种方式。

    这些可以作为您的 App Intents 集成测试。 覆盖每一层后, 您的应用就准备好了, 可以解锁一些真正 强大的体验。 在这个阶段,请务必 手动测试您的 intent, 通过 Siri 和 Shortcuts 应用, 以便像用户一样 亲身体验它们。 这就是 AppIntentsTesting。 一个统一的框架,让您测试 intent、entity、enum, 查询和系统集成—— 全部进程外,全部自动化。

    下载 CometCal 示例项目 亲自尝试, 并探索该应用的 完整测试集。

    本讲座只是触及了 AppIntentsTesting 功能的表面。 请查阅文档以获取 完整的 API 参考。 如果您想了解如何使用 App Intents 构建 Siri 体验, 请查看这场讲座。 现在,您已准备好去构建 超凡脱俗的应用了! 感谢观看!

    • 6:48 - Your first test: execute an intent

      import AppIntentsTesting
      
      func testCreateCalendar() async throws {
          let definitions = IntentDefinitions(bundleIdentifier: "com.example.apple-samplecode.CometCal")
          let createCalendar = definitions.intents["CreateCalendarIntent"]
          let result = try await createCalendar.makeIntent(
              name: "Occupy Saturn",
              color: "red"
          ).run()
          XCTAssertEqual(try result.value.title, "Occupy Saturn")
      }
    • 12:25 - Test an entity string query

      // Testing Entity string queries
      func testEventStringQuery() async throws {
          let results = try await eventEntityDefinition
              .entities(matching: "Cosmic Ray")
      
          XCTAssertEqual(results.count, 1)
          XCTAssertEqual(try results[0].title, "Cosmic Ray Calibration")
      }
    • 13:00 - Implement the EntityStringQuery under test

      // Updated query implementation
      struct EventEntityQuery: EntityStringQuery {
          func entities(for identifiers: [EventEntity.ID]) async throws -> [EventEntity] {
      
          }
      
          func suggestedEntities() async throws -> [EventEntity] {
      
          }
      
          func entities(matching string: String) async throws -> [EventEntity] {
              try calendarManager.fetchEvents()
                  .filter { $0.title.localizedCaseInsensitiveContains(string) }
                  .map(\.entity)
          }
      }
    • 15:42 - Chain multiple intents in one test

      // Test event creation followed by update
      func testCreateAndUpdateEvent() async throws {
          let createResult = try await createEventDefinition.makeIntent(
              title: "Asteroid Dodgeball Practice",
              startDate: Date(),
              isAllDay: false,
              calendar: "Deep Space"
          ).run()
      
          XCTAssertEqual(try createResult.value.title, "Asteroid Dodgeball Practice")
      
          let updateResult = try await updateEventDefinition.makeIntent(
              title: "Asteroid Dodgeball Rules Overview",
              event: createResult.value
          ).run()
      
          XCTAssertEqual(try updateResult.value.title, "Asteroid Dodgeball Rules Overview")
      }
    • 17:45 - Make an intent test-only

      // Test-only intent: SeedSampleEventsIntent
      #if DEBUG
      struct SeedSampleEventsIntent: AppIntent {
          static let isDiscoverable = false
      
          func perform() async throws -> some IntentResult {
              // Create known list of events
              return .result()
          }
      }
      #endif
    • 20:27 - Test Spotlight indexing

      // Testing Spotlight indexing
      func testNewEventIndexedInSpotlight() async throws {
      
          let before = try await eventEntityDefinition.spotlightQuery("Supernova Viewing Party")
          XCTAssertTrue(before.isEmpty, "Event should not exist in Spotlight yet")
      
          // ... Create "Supernova Viewing Party" Event
      
          let after = try await eventEntityDefinition.spotlightQuery("Supernova Viewing Party")
          XCTAssertEqual(after.count, 1)
          XCTAssertEqual(try after[0].title, "Supernova Viewing Party")
      }
    • 22:33 - Test view annotations

      / Testing view annotations
      func testEventViewAnnotation() async throws {
          try await openEventDefinition.makeIntent(target: "Morning Launch Briefing").run()
      
          // Confirm correct event page
          let app = XCUIApplication()
          let title = app.staticTexts["Morning Launch Briefing"]
          XCTAssertTrue(title.waitForExistence(timeout: 5))
      
          let annotations = try await eventEntityDefinition.viewAnnotations()
      
          XCTAssertEqual(annotations.count, 1, "Expected exactly one view annotation")
          XCTAssertEqual(try annotations[0].entity.title, "Morning Launch Briefing")
      }
    • 0:16 - Introduction
    • AppIntentsTesting, a new framework for testing App Intents, which power Siri, Shortcuts, Spotlight, and Widgets. Outlines the agenda: getting started, framework overview, testing intents and entities, and system integrations.

    • 2:01 - Meet CometCal: your first test
    • Introduces the CometCal sample calendar app and writes a first test for CreateCalendarIntent: create a UI testing bundle, build an IntentDefinitions from the bundle id, call makeIntent with parameters, run() it on-device, and assert on the returned entity via dynamic member lookup.

    • 2:29 - How AppIntentsTesting works
    • An integration testing framework that runs your tests in a standard XCUITest bundle while the app runs in a separate process, executing intents through the full App Intents stack, with no mocks and no app-code imports (just a bundle id), giving stable, CI-friendly tests.

    • 9:39 - Testing entity queries
    • Test-driven development of an EntityStringQuery: call entities(matching:) on the entity definition, watch it fail, implement the entities(matching:) conformance on EventEntityQuery, and rerun to green, verified against Shortcuts on device.

    • 13:49 - Combining multiple intents
    • Chain intents in one test as people compose Shortcuts: run CreateEventIntent (with the runtime resolving a CalendarEntity from a string), then pass the returned EventEntity straight into UpdateEventIntent and assert the updated title.

    • 16:27 - Test-only intents
    • Focused intents that exist only for tests, to seed known state, jump directly to a view, or wrap not-yet-adopted functionality. Make any intent test-only with isDiscoverable: false and an #if DEBUG guard.

    • 18:22 - Testing Spotlight indexing
    • Write a regression test for Spotlight: spotlightQuery() returns nothing before the event exists, create it with CreateEventIntent, then assert exactly one indexed result, catching the real bug where indexing was commented out.

    • 20:56 - Testing view annotations
    • Verify the entity Siri sees on screen: open an event via OpenEventIntent, use XCUI to confirm the page, call viewAnnotations(), and assert the single ViewAnnotation's entity, surfacing a bug where the wrong EntityIdentifier (calendar id) was used.

    • 24:00 - The App Intents testing workflow
    • Where AppIntentsTesting fits: unit-test the fundamental types (actions, data, queries) first, then integration-test deeper system reaches (view annotations, Spotlight, cross-app), and still test manually with Siri and Shortcuts.

    • 25:19 - Next steps
    • Download the CometCal sample project and its full test suite, consult the AppIntentsTesting documentation for the complete API, and explore the talk on building Siri experiences with App Intents.

Developer Footer

  • 视频
  • WWDC26
  • 使用 AppIntentsTesting 验证你的 App Intents 采用情况
  • 打开菜单 关闭菜单
    • iOS
    • iPadOS
    • macOS
    • Apple tvOS
    • visionOS
    • watchOS
    打开菜单 关闭菜单
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • SF Symbols
    打开菜单 关闭菜单
    • 辅助功能
    • 配件
    • Apple 智能
    • App 扩展
    • App Store
    • 音频与视频 (英文)
    • 增强现实
    • 设计
    • 分发
    • 教育
    • 字体 (英文)
    • 游戏
    • 健康与健身
    • App 内购买项目
    • 本地化
    • 地图与位置
    • 机器学习与 AI
    • 开源资源 (英文)
    • 安全性
    • Safari 浏览器与网页 (英文)
    打开菜单 关闭菜单
    • 完整文档 (英文)
    • 部分主题文档 (简体中文)
    • 教程
    • 下载
    • 论坛 (英文)
    • 视频
    打开菜单 关闭菜单
    • 支持文档
    • 联系我们
    • 错误报告
    • 系统状态 (英文)
    打开菜单 关闭菜单
    • Apple 开发者
    • App Store Connect
    • 证书、标识符和描述文件 (英文)
    • 反馈助理
    打开菜单 关闭菜单
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program (英文)
    • Mini Apps Partner 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。
    版权所有 © 2026 Apple Inc. 保留所有权利。
    使用条款 隐私政策 协议和准则