Test Station Setup

Versionner les tests matériels avec Git

Apprenez à versionner vos scripts de test matériel avec Git et à lier les résultats de test aux versions de code dans TofuPilot.

JJulien Buteau
beginner7 min de lecture14 mars 2026

Quand un test commence à échouer sur la ligne de production, la première question est toujours : « Qu'est-ce qui a changé ? » Si vos scripts de test ne sont pas versionnés, vous ne pouvez pas y répondre. Git vous donne un historique complet de chaque modification de chaque test. Enregistrer la version du code sur chaque exécution permet de relier un résultat au script exact qui l'a produit.

Ce guide couvre le flux de travail Git pour les projets de test, l'enregistrement des hash de commit sur vos exécutions, et un .gitignore pratique pour les dépôts de tests matériels.

Pourquoi le contrôle de version est important pour les tests matériels

Les scripts de test matériel ne sont pas du code jetable. Ils font partie de votre système qualité. Les régulateurs, les auditeurs et votre futur vous-même ont besoin de savoir :

  • Quelle version du script de test a produit un résultat donné
  • Qui a changé une limite de mesure, et quand
  • Si le test exécuté en DVT est le même que celui exécuté en PVT

Sans Git, vous obtenez des dossiers nommés test_v2_final_FINAL_john.py. Avec Git, vous obtenez une piste d'audit propre.

Flux de travail Git pour les scripts de test

Une stratégie de branches simple fonctionne bien pour les projets de test. Vous n'avez pas besoin de GitFlow. Vous avez besoin de quelque chose que votre équipe utilisera réellement.

git_workflow.txt
main          ──●──●──●──●──●──●──  (tests prêts pour la production)                    \        /feature/add-  ──●──●──●──●          (nouveau test ou modification)thermal-test

main est toujours déployable sur les stations de production. Chaque commit sur main a été revu et testé.

Les branches de fonctionnalité sont l'endroit où vous développez de nouveaux tests ou modifiez les existants. Nommez-les de manière descriptive : feature/add-thermal-cycling, fix/dmm-timeout-handling, update/voltage-limits-rev-c.

Flux de travail de base :

workflow_commands.sh
# Démarrer une nouvelle modification de testgit checkout -b feature/add-current-measurement# Faites vos modifications, testez localementgit add tests/power_rail_fct.pygit commit -m "Add idle current measurement to power rail FCT"# Poussez et créez une pull request pour revuegit push -u origin feature/add-current-measurement# Après revue, fusionnez dans maingit checkout maingit pullgit merge feature/add-current-measurementgit push

Taguez les releases quand vous déployez sur les stations de production :

tagging.sh
# Taguer une release avant le déploiement en productiongit tag -a v1.2.0 -m "Add thermal cycling test, update voltage limits for Rev C"git push origin v1.2.0

Lire le hash de commit Git à l'exécution

Liez chaque exécution de test au code exact qui l'a produite. C'est le lien de traçabilité clé entre vos résultats de test et votre code de test.

git_version.py
39 lines
import subprocessdef get_git_info() -> dict:    """Récupère le hash de commit et le tag Git courants."""    info = {}    try:        info["commit"] = subprocess.check_output(            ["git", "rev-parse", "HEAD"],            stderr=subprocess.DEVNULL,        ).decode().strip()        info["commit_short"] = subprocess.check_output(            ["git", "rev-parse", "--short", "HEAD"],            stderr=subprocess.DEVNULL,        ).decode().strip()        # Vérifier s'il y a des modifications non commitées        status = subprocess.check_output(            ["git", "status", "--porcelain"],            stderr=subprocess.DEVNULL,        ).decode().strip()        info["dirty"] = len(status) > 0        # Récupérer le dernier tag si disponible        try:            info["tag"] = subprocess.check_output(                ["git", "describe", "--tags", "--abbrev=0"],                stderr=subprocess.DEVNULL,            ).decode().strip()        except subprocess.CalledProcessError:            info["tag"] = None    except subprocess.CalledProcessError:        info["commit"] = "unknown"        info["commit_short"] = "unknown"        info["dirty"] = True        info["tag"] = None    return info

Cela suppose que Git est installé sur la station et que le script s'exécute dans l'arbre de travail. Si vous déployez un exécutable empaqueté, capturez la version au moment du build et lisez-la depuis un fichier, car git rev-parse échouera sur la station.

Enregistrer la version du code sur chaque exécution

Enregistrez la version comme mesure. Les mesures sont stockées par exécution et sont filtrables, ce qui permet de comparer les exécutions réussies et échouées par version de code.

test_with_version.py
41 lines
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import uploadfrom git_version import get_git_infogit_info = get_git_info()# Avertir si l'exécution se fait avec des modifications non commitées en productionif git_info["dirty"]:    print("ATTENTION : Exécution de tests avec des modifications non commitées")@htf.measures(    htf.Measurement("script_version").doc("Tag Git ou commit court du script de test"),    htf.Measurement("script_dirty").doc("Vrai si l'arbre de travail avait des modifications non commitées"),)def record_script_version(test):    test.measurements.script_version = git_info.get("tag") or git_info["commit_short"]    test.measurements.script_dirty = git_info["dirty"]@htf.measures(    htf.Measurement("voltage_3v3").in_range(3.2, 3.4).with_units(units.VOLT),)def test_power_rail(test):    test.measurements.voltage_3v3 = 3.29def main():    test = htf.Test(        record_script_version,        test_power_rail,        procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",  # UUID de procédure du dashboard        part_number="PCBA-100",    )    test.add_output_callbacks(upload())    test.execute(lambda: "DUT-001")if __name__ == "__main__":    main()

Chaque exécution porte désormais la version du code qui l'a produite. Quand un test commence à échouer après un déploiement, filtrez par script_version et comparez les exécutions réussies aux échouées pour isoler le changement.

Enregistrer script_dirty à côté vaut la ligne supplémentaire. Une exécution produite depuis un arbre de travail non commité n'est reproductible depuis aucun commit : mieux vaut que ce soit signalé dans les données plutôt qu'affiché dans une console que personne ne lit.

Une précision sur l'emplacement : les champs promus sur l'exécution elle-même forment un ensemble fixe (procedure_id, part_number, revision, batch_number, sub_units, operated_by). Tout ce que vous placez d'autre sur test.metadata reste sur l'objet Python et n'est pas persisté, d'où l'enregistrement de la version comme mesure plutôt que comme métadonnée d'exécution.

Si vous déployez vos procédures depuis un push Git, c'est déjà géré : chaque déploiement est un artefact immuable lié à un commit, donc l'exécution enregistre quel déploiement l'a produite sans code de votre part.

Modèle .gitignore pour les projets de test

Les dépôts de tests matériels ont des fichiers spécifiques que vous ne voulez pas suivre. Voici un point de départ pratique.

.gitignore
42 lines
# Python__pycache__/*.py[cod]*.so*.egg-info/dist/build/venv/.venv/# Environnement et secrets.env.env.*!.env.example# IDE.vscode/.idea/*.swp*.swo# Artefacts de test (logs, rapports, captures)logs/test_output/*.log*.csvcaptures/screenshots/# Données de calibration des instruments (spécifiques à la station)cal_data/fixture_cal/# Fichiers système.DS_StoreThumbs.db# PyInstaller (si vous empaquetez les tests)*.spec# Surcharges de configuration localeconfig/local.yaml

Quelques notes sur ce qui est exclu :

  • Les fichiers .env contiennent des clés API. Ne les commitez jamais. Incluez un .env.example avec des valeurs fictives pour que les nouveaux membres de l'équipe sachent quoi configurer.
  • logs/ et test_output/ sont générés par exécution. Leur place est avec vos résultats de test, pas dans Git.
  • cal_data/ contient les données de calibration spécifiques à la station. Elles n'ont pas leur place dans le dépôt des scripts de test.
  • config/local.yaml est pour les surcharges par développeur. Les configurations partagées (config/dev.yaml, config/production.yaml) restent suivies.

Une réserve sur la ligne *.csv : elle vise les sorties de test générées, mais elle ignorera aussi silencieusement un CSV que vous vouliez suivre, comme une table de limites ou une référence de calibration. Si vous gardez des fichiers de données dans le dépôt, restreignez ce motif aux répertoires qui contiennent réellement des sorties.

Plus de guides

Mettez ce guide en pratique