Une photo haute résolution n’occupe qu’une petite cellule dans une liste iOS, mais son décodage peut se répéter lors d’un défilement rapide. Si le code charge d’abord l’image originale avant de réduire le UIImage à la taille affichée, l’écran montre une vignette alors que le décodage a peut-être déjà traité l’image entière. Pour les tests de régression exécutés sur un Mac cloud, il est plus fiable de rendre vérifiable la règle « aucune vignette ne dépasse la limite de pixels prévue » que de se contenter d’observer la fluidité de la liste.
Définir la limite en pixels plutôt que deviner la taille du fichier
Cet article prend une longueur maximale de 320 pixels pour les tests, sans en faire une valeur universelle pour toutes les interfaces. Dans un projet réel, la taille demandée doit être déduite des dimensions de la cellule en points, du facteur d’échelle de l’écran cible et du mode de recadrage. Sur un écran à forte densité, par exemple, les dimensions en pixels ne peuvent pas être calculées à partir des seuls points de la cellule. Une fois la limite fixée, faites-la accepter en paramètre par le point d’entrée du chargement des images ; évitez de répéter une constante dans chaque contrôleur de liste.
Ajoutez au bundle de tests un JPEG nommé landscape.jpg. Ses deux dimensions d’origine doivent dépasser la limite testée : sinon, le test pourrait réussir à tort même si l’implémentation renvoie directement l’image originale. Versionnez cet échantillon avec le dépôt au lieu de le télécharger à la volée. Conservez aussi des images d’autres proportions, en paysage et en portrait, pour ne pas tester une seule disposition. Vérifiez la configuration des ressources de la cible de tests afin de confirmer que le fichier est bien accessible à l’exécution depuis son bundle.
Une assertion sur les dimensions indique « quelle taille fait l’image produite », pas « quelle quantité de mémoire a été utilisée au pic ». Ces deux points doivent être validés séparément.
Créer la vignette au point d’entrée du décodage
Utilisez ImageIO pour créer une source d’image à partir de l’URL du fichier, puis fixez la longueur maximale en pixels lors de la création de la vignette. La fonction d’exemple renvoie un CGImage, dont le test peut lire directement les dimensions en pixels ; si l’interface a besoin d’un UIImage, effectuez la conversion à l’endroit où la fonction est appelée. Désactivez la mise en cache immédiate lors de la création de la source pour éviter de déclencher d’abord le décodage de l’image originale. Demandez en revanche le décodage immédiat de la vignette lors de sa création.
import Foundation
import ImageIO
func makeThumbnail(at url: URL, maxPixelSize: Int) -> CGImage? {
guard maxPixelSize > 0 else { return nil }
let sourceOptions: [CFString: Any] = [
kCGImageSourceShouldCache: false
]
guard let source = CGImageSourceCreateWithURL(
url as CFURL, sourceOptions as CFDictionary
) else {
return nil
}
let thumbnailOptions: [CFString: Any] = [
kCGImageSourceCreateThumbnailFromImageAlways: true,
kCGImageSourceCreateThumbnailWithTransform: true,
kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
kCGImageSourceShouldCacheImmediately: true
]
return CGImageSourceCreateThumbnailAtIndex(
source, 0, thumbnailOptions as CFDictionary
)
}
CreateThumbnailFromImageAlways garantit ici que le test passe bien par la création d’une vignette ; CreateThumbnailWithTransform applique les informations d’orientation à l’image produite. Selon l’orientation de l’échantillon, largeur et hauteur peuvent être inversées : l’assertion doit donc vérifier le maximum des deux, et non imposer « la largeur doit dépasser la hauteur » à toutes les images. La fonction renvoie nil si l’entrée est invalide ou indécodable. L’interface doit prévoir un état d’échec visible plutôt que supposer que tous les fichiers sont valides.
Tester les dimensions avec un échantillon fixe
Placez la fonction de production dans la cible de l’application et rendez-la accessible à la cible de tests. Le test ci-dessous suppose que la ressource a été ajoutée au bundle de tests ; si elle se trouve dans un sous-dossier, adaptez sa recherche à l’organisation du projet. XCTUnwrap signale directement où survient l’échec si l’échantillon manque ou si le décodage échoue, au lieu de laisser une valeur optionnelle passer inaperçue.
import XCTest
import ImageIO
@testable import Sample
final class ThumbnailTests: XCTestCase {
func testThumbnailRespectsPixelLimit() throws {
let url = try XCTUnwrap(
Bundle(for: Self.self).url(
forResource: "landscape",
withExtension: "jpg"
)
)
let image = try XCTUnwrap(
makeThumbnail(at: url, maxPixelSize: 320)
)
XCTAssertGreaterThan(image.width, 0)
XCTAssertGreaterThan(image.height, 0)
XCTAssertLessThanOrEqual(
max(image.width, image.height), 320
)
}
func testRejectsInvalidLimit() throws {
let url = try XCTUnwrap(
Bundle(for: Self.self).url(
forResource: "landscape",
withExtension: "jpg"
)
)
XCTAssertNil(makeThumbnail(at: url, maxPixelSize: 0))
}
}
Remplacez Sample par le nom réel du module. En complément du test de dimensions, ajoutez un fichier corrompu pour vérifier que le code appelant sait gérer nil, ainsi qu’une image portant des informations d’orientation pour confirmer que son affichage correspond au résultat attendu. Les images de test doivent avoir une provenance et des droits d’utilisation clairement établis : ne versez pas de photos personnelles dans le dépôt.
Exécuter les tests sur un Mac cloud et examiner les faux signalements
Commencez par consulter la liste des simulateurs installés avec xcrun simctl list devices available, puis choisissez un appareil réellement disponible comme destination de xcodebuild. Remplacez également le nom du projet, le scheme et la cible de tests par ceux du dépôt ; ne reprenez pas les paramètres de l’exemple en supposant que l’appareil indiqué est disponible.
xcrun simctl list devices available
xcodebuild \
-project Sample.xcodeproj \
-scheme Sample \
-destination 'platform=iOS Simulator,name=iPhone 16' \
-only-testing:SampleTests/ThumbnailTests \
test
Si le test indique que l’image est introuvable, vérifiez d’abord qu’elle appartient aux ressources de la cible de tests, plutôt que d’augmenter la limite de taille. Si l’image produite dépasse cette limite, confirmez que la liste appelle bien makeThumbnail et ne repasse pas par l’ancien chemin qui crée d’abord un UIImage à partir de l’image originale. En CI, conservez aussi la sortie de commande des tests en échec et utilisez toujours les mêmes échantillons. Changer d’images sans vérifier leurs dimensions en pixels et leur orientation rendrait deux exécutions incomparables.
Valider les dimensions et observer la mémoire séparément
Un test de dimensions peut être exécuté à chaque commit, mais il ne reproduit ni la conservation simultanée de plusieurs images par une vraie liste, ni l’effet du cache d’images et du défilement rapide. Avant l’intégration, faites défiler à plusieurs reprises la liste sur l’appareil cible avec un ensemble d’images représentatif, en suivant le parcours réel de l’application. Observez le pic de mémoire et la libération des images. Consignez l’appareil, la version du système, le nombre d’images et les étapes suivies avant de comparer les résultats d’avant et d’après la modification ; n’extrapolez pas à tous les appareils une seule mesure prise sur simulateur.
Enfin, vérifiez trois points : la taille demandée pour les vignettes découle-t-elle des besoins d’affichage ? Tous les points d’entrée des images passent-ils par la même fonction de sous-échantillonnage ? Les images invalides disposent-elles d’un traitement visible ? Les tests automatisés sur Mac cloud protègent ainsi la limite en pixels, tandis que les mesures sur appareil répondent à la question de la mémoire réellement utilisée. Chaque preuve a son propre périmètre.
Questions fréquentes
Redimensionner un UIImage déjà chargé suffit-il ?
Non. Le fichier source peut déjà avoir été décodé en entier. Il faut fixer la limite de pixels au moment où ImageIO crée la vignette.
Un test de dimensions réussi garantit-il une faible consommation mémoire ?
Non. Il vérifie les pixels de sortie. Mesurez séparément le pic de mémoire sur un appareil cible, avec des images et un défilement représentatifs.
Configurez un Mac cloud pour votre prochain projet
Choisissez votre Mac mini selon la mémoire ou la charge de compilation. Trois configurations sont disponibles à la location à la journée, à la semaine, au mois ou au trimestre. Vérifiez la disponibilité des nœuds en temps réel depuis la console.