Un raccourci « Enregistrer une lecture » est disponible sur la machine de développement, mais n’apparaît pas dans le simulateur d’une machine de build distante. Avant de modifier le code métier, distinguez trois vérifications : la validité des paramètres, l’exécution de l’Intent et la découverte de l’action par le système. Un Mac cloud permet de stabiliser l’environnement de test des deux premières ; la dernière doit toujours être validée dans un simulateur où l’application est installée.
Délimiter d’abord les tests automatisés
Pour vérifier la démarche, prenons une action qui n’écrit rien sur le disque : elle reçoit un identifiant de livre, supprime les espaces en début et en fin de chaîne, puis renvoie l’identifiant normalisé. On écarte ainsi d’abord les problèmes d’autorisations de stockage et les aléas du réseau. Lorsque l’action utilisera une base de données, il faudra tester séparément l’écriture et le comportement en cas d’exécution répétée : un résultat « réussi » ne prouve pas que les données ont été enregistrées.
La validation comporte trois niveaux : des tests Swift purs vérifient les valeurs vides et les caractères interdits ; XCTest appelle perform() et contrôle le résultat ainsi que les erreurs ; une vérification manuelle dans le simulateur confirme que l’action est visible, que le paramètre peut être renseigné et que le résultat est lisible. Un échec aux deux premiers niveaux doit bloquer la fusion. Le troisième dépend de l’indexation du système : faites-en un contrôle avant la publication d’une version, plutôt qu’un test fondé sur une attente d’une durée fixe.
Ne désinstallez et ne réinstallez pas l’application en boucle dans un test automatisé pour attendre l’apparition du raccourci. Vérifiez d’abord le contrat du code, puis examinez l’installation, le lancement de l’application et la découverte de l’action par le système.
Extraire les règles de saisie dans un type directement testable
Les règles ci-dessous acceptent de 1 à 32 caractères parmi les lettres ASCII, les chiffres, les traits de soulignement et les traits d’union. Les espaces ne sont autorisés qu’aux extrémités de la saisie ; les autres caractères produisent une erreur explicite. Dans cet exemple, perform() renvoie seulement l’identifiant, sans effet de bord persistant.
import AppIntents
import Foundation
enum ReadingIDError: LocalizedError {
case invalid
var errorDescription: String? {
"编号须为 1–32 位字母、数字、下划线或连字符"
}
}
enum ReadingID {
static func normalize(_ raw: String) throws -> String {
let value = raw.trimmingCharacters(in: .whitespacesAndNewlines)
let pattern = #"^[A-Za-z0-9_-]{1,32}$"#
guard value.range(of: pattern, options: .regularExpression) != nil else {
throw ReadingIDError.invalid
}
return value
}
}
struct CheckReadingIDIntent: AppIntent {
static var title: LocalizedStringResource = "检查书籍编号"
static var openAppWhenRun = false
@Parameter(title: "书籍编号")
var bookID: String
func perform() async throws -> some IntentResult & ReturnsValue<String> {
let normalized = try ReadingID.normalize(bookID)
return .result(value: normalized)
}
}
Placez le titre du paramètre, celui de l’action et le message d’erreur dans les ressources de localisation du projet. Les libellés chinois ne sont ici que des exemples : ils ne doivent pas constituer les seuls textes livrés avec une application multilingue. La règle elle-même n’accepte que des identifiants ASCII. Si votre activité autorise les caractères chinois ou d’autres écritures, définissez d’abord le jeu de caractères admis, puis adaptez l’expression et les cas de test.
Tester les cas limites, pas seulement les saisies valides
Vérifiez au minimum que " book_7 " renvoie "book_7" et que la chaîne vide, les espaces internes et les identifiants de plus de 32 caractères sont rejetés. Pour les cas d’erreur, vérifiez le type de l’erreur, pas seulement qu’« une erreur a été levée » : une défaillance inattendue d’une dépendance pourrait sinon faire réussir le test. Lorsque vous testez perform(), assurez-vous aussi que sa valeur de retour respecte la règle de normalisation. Séparez les tests de la règle pure de ceux qui appellent l’Intent : en cas d’échec, vous saurez si la règle de saisie ou l’interface avec le système a changé.
Déclarer l’action et la vérifier dans le simulateur
Pour que le système puisse proposer une action, ajoutez AppShortcutsProvider à la cible de l’application. Conservez le marqueur du nom de l’application dans la phrase : il permet au système d’associer l’action à l’application en cours. Ce n’est pas une chaîne shell.
import AppIntents
struct ReadingShortcuts: AppShortcutsProvider {
static var appShortcuts: [AppShortcut] {
AppShortcut(
intent: CheckReadingIDIntent(),
phrases: ["在 \(.applicationName) 检查书籍编号"],
shortTitle: "检查书籍编号",
systemImageName: "book"
)
}
}
Vérifiez d’abord que ce fichier appartient à la cible de l’application, et pas uniquement à celle des tests. Installez l’application compilée et lancez-la une fois. Ouvrez ensuite « Raccourcis » dans le simulateur, recherchez l’action par son titre, saisissez un identifiant valide et exécutez-la. Soumettez ensuite un identifiant invalide et vérifiez que l’erreur est compréhensible. Si l’action n’apparaît pas, consignez la version du système, la version du build de l’application et l’ordre des opérations après l’installation. Ne présentez pas son apparition fortuite après la réouverture d’un écran comme une solution fiable.
Fixer le simulateur et le répertoire des résultats
Sur un Mac cloud ZSHMac, lancez d’abord xcrun simctl list devices available pour afficher les simulateurs installés et disponibles, choisissez l’UDID d’un appareil et définissez SIM_UDID. La commande suivante suppose que le projet possède un scheme partagé nommé Reader ; utilisez celui de votre projet lors de l’exécution. Attribuez un nouveau chemin au paquet de résultats à chaque lancement pour éviter qu’un fichier existant ne fasse échouer immédiatement la commande de test.
mkdir -p artifacts
test -n "${SIM_UDID:-}" || { printf '%s\n' 'SIM_UDID is required' >&2; exit 1; }
result="$PWD/artifacts/app-intents-$(date +%Y%m%d-%H%M%S)-$$.xcresult"
xcodebuild test \
-scheme Reader \
-destination "platform=iOS Simulator,id=$SIM_UDID" \
-resultBundlePath "$result"
En CI, conservez le code de sortie de la commande et le paquet de résultats : le premier détermine si la tâche a réussi, le second permet d’identifier le cas de test en échec. Si le scheme n’est pas partagé ou si le simulateur visé n’est pas disponible, corrigez d’abord la configuration d’exécution ; ne classez pas cela comme un défaut de logique de l’Intent. Pour la validation manuelle, consignez si l’action apparaît, si l’indication de saisie est correcte et ce qui se passe réellement avec des paramètres valides et invalides.
Diagnostiquer les échecs niveau par niveau
| Symptôme | À vérifier d’abord | À ne pas faire en premier |
|---|---|---|
| Échec d’un test de la règle pure | Plage de caractères, longueur et traitement des espaces aux extrémités | Réinstaller le simulateur |
Résultat de perform() incorrect |
Transmission du paramètre et type de la valeur renvoyée | Attendre l’indexation du système |
| La commande de test ne trouve pas l’appareil | Liste des appareils disponibles et UDID | Modifier la règle Swift |
| L’action est absente de Raccourcis | Appartenance du fichier à la cible de l’application, installation et premier lancement | Ajouter une attente fixe au test |
| L’action apparaît, mais son exécution échoue | Indication du paramètre, type d’erreur et version du système cible | Ignorer toutes les erreurs |
Cette vérification par niveaux sert à circonscrire la panne, pas à garantir que l’action sera visible dans le système dès l’installation. La validation n’est complète que lorsque les tests du code réussissent et que l’action a été vérifiée dans le simulateur avec des saisies valides et invalides. Après l’ajout d’une véritable écriture, prévoyez aussi des tests d’exécution répétée et de persistance des données : le critère de réussite de cet exemple, qui ne fait que renvoyer un identifiant, ne suffira plus.
Questions fréquentes
Pourquoi l’action est-elle absente de Raccourcis malgré la réussite de XCTest ?
Vérifiez que l’app contenant AppShortcutsProvider est installée et a été lancée, ainsi que la version du système et la configuration de la cible. L’indexation peut prendre du temps.
Où placer la validation des paramètres ?
Placez les règles réutilisables dans un type Swift distinct, appelé depuis perform(). Les tests unitaires ne dépendront ainsi pas de l’indexation du système.
Une CI sans interface graphique suffit-elle ?
Non. La CI vérifie les entrées et les valeurs renvoyées ; l’affichage de l’action et la demande de paramètres doivent être contrôlés sur un simulateur ou un appareil cible.
Besoin d’un Mac cloud dédié ?
Choisissez le modèle, la région et la durée de facturation. Vous bénéficiez d’une machine physique dédiée ; la disponibilité réelle est indiquée en temps réel dans la console.