Tester les distances iOS et les limites de géorepérage sur un Mac cloud

Tester les distances iOS et les limites de géorepérage sur un Mac cloud

Tester les distances iOS et les limites de géorepérage sur un Mac cloud

Si un commerce à proximité apparaît soudain à des dizaines de milliers de kilomètres, le service de localisation n’est pas forcément en cause. Des coordonnées inversées, une simple soustraction de part et d’autre de l’antiméridien ou un arrondi effectué avant de vérifier la distance peuvent produire le même symptôme. Sur un Mac cloud GNUMac, commencez par valider les calculs avec des coordonnées fixes, puis rebranchez les données de localisation et les callbacks de l’appareil. En cas d’échec, vous saurez ainsi quelle couche examiner, sans déplacer sans cesse la carte pour tenter de comprendre.

Définir d’abord le contrat des coordonnées et des distances

Cet article vérifie la « distance à la surface de la Terre entre deux coordonnées ». Il ne s’agit ni de la longueur d’un itinéraire routier, ni de la distance réellement parcourue par l’utilisateur. Les coordonnées sont fournies en degrés décimaux, avec la latitude en premier et la longitude en second. Tous les calculs internes utilisent des mètres ; la conversion d’unité n’intervient qu’à l’affichage.

La latitude doit être comprise entre −90 et +90 degrés, et la longitude entre −180 et +180 degrés. Les valeurs non finies doivent également être rejetées. Ne ramenez pas silencieusement une valeur invalide à la borne la plus proche : une donnée corrompue en amont deviendrait alors un enregistrement apparemment normal.

Des coordonnées valides ne garantissent pas une localisation fiable. Le point de latitude zéro et de longitude zéro est une position valide : il ne faut pas systématiquement l’interpréter comme une « position non encore obtenue ». Son acceptation dépend du contrat de la source de données.

La distance à l’écran sur une carte ne peut pas non plus servir de valeur attendue. La projection, le niveau de zoom et les pixels de l’appareil modifient le rendu, mais ne doivent pas modifier les calculs métier.

Exécuter des jeux de données fixes sur un Mac cloud

Préparez un environnement macOS dans lequel la chaîne de développement voulue est sélectionnée, puis exécutez xcrun swift --version pour vérifier que le compilateur est disponible. Enregistrez le contenu suivant dans distance-check.swift. Ce script ne lit pas la position actuelle, ne demande aucune autorisation de localisation et n’accède pas au réseau.

import Foundation
import CoreLocation

enum CoordinateError: Error {
    case invalid
}

func point(_ latitude: Double, _ longitude: Double) throws -> CLLocation {
    let coordinate = CLLocationCoordinate2D(
        latitude: latitude,
        longitude: longitude
    )
    guard latitude.isFinite,
          longitude.isFinite,
          CLLocationCoordinate2DIsValid(coordinate) else {
        throw CoordinateError.invalid
    }
    return CLLocation(latitude: latitude, longitude: longitude)
}

func rejects(_ latitude: Double, _ longitude: Double) -> Bool {
    do {
        _ = try point(latitude, longitude)
        return false
    } catch {
        return true
    }
}

let origin = try point(0, 0)
precondition(origin.distance(from: origin) == 0)

let east = try point(0, 179.9)
let west = try point(0, -179.9)
let crossing = east.distance(from: west)
precondition(crossing > 20_000 && crossing < 23_000)
precondition(abs(crossing - west.distance(from: east)) < 1)

let polarA = try point(89.9, 0)
let polarB = try point(89.9, 180)
let polarDistance = polarA.distance(from: polarB)
precondition(polarDistance > 20_000 && polarDistance < 23_000)

precondition(rejects(91, 0))
precondition(rejects(0, 181))
precondition(rejects(.nan, 0))
precondition(rejects(0, .infinity))

Lancez ensuite la commande ci-dessous. Si toutes les assertions passent, le script ne produit aucune sortie. En cas d’échec, il se termine avec un code non nul : il peut donc être utilisé directement comme étape de pipeline.

xcrun swift distance-check.swift

Ces intervalles constituent des marges de tolérance larges pour les données de test, et non des mesures de performance ou une garantie de précision métier. Deux points situés de part et d’autre de l’antiméridien peuvent être très proches. De même, près des pôles, un grand écart de longitude ne signifie pas que les points sont séparés par la moitié du globe. Ces deux cas permettent de détecter l’erreur qui consiste à soustraire directement les latitudes et les longitudes comme dans un plan.

Isoler la règle de frontière du géorepérage dans une fonction pure

Supposons que la règle métier soit la suivante : « une distance inférieure ou égale au rayon signifie que le point est à l’intérieur ». Testez d’abord le comparateur avec des distances définies manuellement, puis raccordez-y les résultats du calcul à partir des coordonnées. Vous éviterez ainsi de déboguer deux couches à la fois. Ajoutez le code suivant à la fin du même fichier, puis relancez-le.

func isInside(distance: Double, radius: Double) -> Bool {
    guard distance.isFinite, radius.isFinite,
          distance >= 0, radius >= 0 else {
        return false
    }
    return distance <= radius
}

precondition(isInside(distance: 499.9, radius: 500))
precondition(isInside(distance: 500, radius: 500))
precondition(!isInside(distance: 500.1, radius: 500))
precondition(!isInside(distance: .nan, radius: 500))
precondition(!isInside(distance: 0, radius: -1))

let meters = 1_250.0
precondition(meters / 1_000 == 1.25)

Les tests de frontière doivent inclure le cas d’égalité exacte, et pas seulement des points manifestement à l’intérieur ou à l’extérieur. Ne déduisez pas le résultat d’une chaîne affichant « 0,5 km » : plusieurs distances brutes peuvent être arrondies au même texte.

Pour limiter les basculements répétés à proximité de la frontière, le produit peut définir une stratégie d’hystérésis avec des seuils distincts pour l’entrée et la sortie. Il s’agit alors d’une machine à états, qui exige des tests supplémentaires sur des séquences d’entrées successives. Il ne suffit pas d’ajouter arbitrairement une constante de tolérance au comparateur.

Ne pas confondre précision de localisation et tolérance de calcul

Les échantillons de position réels comportent aussi un horodatage et une précision horizontale. La couche d’intégration doit rejeter explicitement les échantillons trop anciens et traiter les valeurs négatives de précision horizontale. Même valides, des coordonnées peu précises ne doivent pas déclencher directement un événement d’« entrée confirmée ».

Voici une règle prudente et vérifiable : soient d la distance, a la précision horizontale et r le rayon. Le point n’est considéré comme certainement à l’intérieur que si d+a≤r, et comme certainement à l’extérieur que si d−a>r. Dans tous les autres cas, son état est indéterminé. Il s’agit d’une décision métier conservatrice, pas d’une interprétation de la précision comme une borne d’erreur absolue garantie.

Pendant les tests, injectez séparément des échantillons précis, imprécis, trop anciens et invalides. Vérifiez que l’état indéterminé est conservé et que l’interface n’affiche pas à tort une conclusion certaine. N’élargissez pas les tolérances des assertions de calcul pour masquer le bruit de localisation.

Conserver les éléments de preuve et réintégrer le code au projet iOS

Le script ci-dessus permet de revérifier rapidement le comportement du framework. Lors de l’intégration définitive, placez la validation des coordonnées et le comparateur dans un module testable, puis faites appeler directement l’implémentation de production par la cible de tests. Ne maintenez qu’une seule version de l’algorithme : un script correct ne doit pas masquer une application qui utilise encore l’ancienne logique.

Pour chaque exécution, conservez l’identifiant du commit, la version de la chaîne de développement, les coordonnées du jeu de test, les distances brutes en mètres et les assertions en échec. Après une mise à jour du système, déterminez d’abord si l’échec concerne la validation des entrées, l’intervalle de distance ou la politique de gestion des états. Ne remplacez pas d’emblée toutes les valeurs attendues.

Enfin, prévoyez une phase de recette sur un appareil iOS physique : les événements de surveillance de régions, l’exécution en arrière-plan et les déplacements réels relèvent d’une autre chaîne de fonctionnement. La réussite des tests de calcul prouve uniquement que des entrées fixes produisent des résultats conformes au contrat. Consigner cette limite dans le compte rendu de recette est plus utile que d’ajouter des coordonnées aléatoires.

Questions fréquentes

Le script suffit-il à valider le géorepérage iOS ?

Non. Il vérifie les coordonnées, les distances et la politique de seuil. Les événements de région, le fonctionnement en arrière-plan et la précision réelle exigent des tests sur appareil iOS.

Peut-on décider de l’entrée dans une zone avec la distance affichée ?

Non. Comparez la distance brute en mètres au seuil métier. La conversion et l’arrondi appartiennent à l’affichage ; la précision de localisation suit une politique distincte.

Configurez un Mac mini dédié pour votre workflow

Choisissez le modèle, la région et la durée selon votre projet. Vérifiez la mémoire, le stockage et la connectivité avant de commander. La disponibilité réelle est indiquée en temps réel dans la console.

Définissez d’abord votre workflow, puis démarrez votre machine.

Un Mac mini physique dédié. Choisissez le modèle, la région et la durée, puis configurez le stockage selon les besoins de votre projet.