Migrating from Legacy Systems

Où stocker les résultats de test

Les résultats de test éparpillés dans des tableurs et des dossiers partagés cessent de fonctionner à un moment prévisible. Quand migrer, et vers quoi.

JJulien Buteau
beginner8 min de lecture14 mars 2026

La plupart des équipes matériel enregistrent les résultats de test de production dans un tableur. Ça marche, jusqu'au jour où non, et l'échec se décrit toujours de la même façon : les résultats sont éparpillés, dans des dossiers au hasard sur les portables, le disque partagé et le cloud, et le tableur est devenu trop lourd à maintenir.

Ce guide couvre le moment où un tableur cesse d'être la bonne réponse, vers quoi migrer, et comment le faire sans perdre l'historique.

Quand un tableur suffit vraiment

À dire d'abord, parce que la réponse n'est pas toujours « achetez quelque chose ».

Un tableur convient quand une personne enregistre les résultats d'une station, les volumes sont faibles, et personne n'a besoin de répondre à des questions sur des mois de données. Les prototypes et les préséries entrent confortablement dans ce cas.

Les signaux que ça ne marche plus sont précis :

  • Deux personnes doivent enregistrer en même temps. Les tableurs sont mono-écrivain en pratique.
  • Quelqu'un demande le rendement sur une période. Répondre implique un tableau croisé qui casse au prochain déplacement de colonne.
  • Une unité retournée a besoin de son historique. Retrouver un numéro de série dans un an de fichiers est une recherche manuelle.
  • La personne qui a construit le tableur est la seule à savoir le maintenir. C'est le problème du facteur bus, et c'est généralement ce qui force le changement.

Le modèle tableur

Un journal de test de production typique :

Numéro de sérieDateOpérateurRésultatTension (V)Courant (A)FirmwareNotes
SN-0012025-01-15AlicePASS3,310,52v2.1
SN-0022025-01-15BobFAIL3,580,89v2.1Dépassement de courant
SN-0032025-01-16AlicePASS3,290,48v2.1

Les problèmes structurels :

  • Pas d'accès simultané. Deux opérateurs ne peuvent pas enregistrer en même temps sans risque d'écrasement.
  • Pas de validation. Rien n'empêche « PSAS » au lieu de « PASS », ou la tension dans la colonne du courant.
  • Pas d'analytique. Rendement, capabilité et tendances impliquent des formules fragiles.
  • Pas d'historique. Modifiez une cellule et la valeur d'origine disparaît.
  • Les limites vivent dans votre tête. Le tableur enregistre 3,31 mais pas que la limite était 3,1 à 3,5. Quand les limites changent, les anciennes lignes deviennent ininterprétables.

Ce dernier point est le plus dommageable et le moins remarqué.

Option 1 : votre propre base de données

Un schéma Postgres avec des tables unit, run, step et measurement, plus Metabase ou Grafana par-dessus, est une réponse parfaitement respectable. Elle gère la concurrence, donne du SQL pour toute question, et ne coûte rien en licence.

Le piège n'est pas la construction, c'est la maintenance. Le rendement est facile. Ce qui prend du temps : la capabilité calculée correctement par mesure, des limites de contrôle qui survivent à un changement de spécification, un rendement au premier passage qui compte le premier run par unité plutôt que n'importe quel run réussi, et la traçabilité des sous-ensembles. Chacun est un petit projet. Ensemble, ils constituent ce que personne n'a le temps de maintenir.

Choisissez cette voie si quelqu'un peut en assumer la charge et que vos besoins ne correspondent à aucun produit.

Option 2 : une plateforme de données de test

L'alternative est un système conçu pour ça, où le schéma et les analyses viennent avec.

Voici le même test que le tableur ci-dessus, écrit en OpenHTF avec enregistrement automatique :

power_board_test.py
28 lines
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import upload@htf.measures(    htf.Measurement("voltage").with_units(units.VOLT).in_range(3.1, 3.5),    htf.Measurement("current").with_units(units.AMPERE).in_range(maximum=0.7),)def power_supply_check(test):    voltage = 3.31  # Lire depuis votre instrument    current = 0.52    test.measurements.voltage = voltage    test.measurements.current = currentdef main():    test = htf.Test(        power_supply_check,        procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",  # UUID de procédure du dashboard        part_number="PCB-V1",    )    test.add_output_callbacks(upload())    test.execute(lambda: "SN-001")if __name__ == "__main__":    main()

Installez-le avec pip install "tofupilot[openhtf]". Le callback upload() lit TOFUPILOT_API_KEY dans l'environnement.

Chaque run capture le numéro de série, le verdict, chaque mesure avec ses limites et unités, les horodatages et l'identité de la station. La définition de mesure dans le code de test est le schéma : rien de séparé à concevoir ou migrer.

Ce qui change

CapacitéTableurBase maisonPlateforme
SaisieManuelleDepuis le codeDepuis le code
Accès simultanéMono-écrivainOuiOui
Limites stockées avec les résultatsNonSi modéliséOui
Tendances de rendementFormules manuellesSQL à écrireIntégré
Capabilité et cartes de contrôleMacrosÀ construireIntégré
Pareto des défaillancesFiltrage manuelSQL à écrireIntégré
Traçabilité sous-ensemblesNonSi modéliséIntégré
Piste d'auditAucuneSi modéliséHistorique complet
Coût récurrentVotre tempsTemps d'ingénierieLicence

Conserver vos données existantes

Les données historiques s'importent via l'API. Structurez chaque ligne comme un run avec une phase et ses mesures :

import_from_csv.py
49 lines
import csvimport osfrom datetime import datetime, timezonefrom tofupilot.v2 import TofuPilotPROCEDURE_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"with TofuPilot(api_key=os.getenv("TOFUPILOT_API_KEY")) as client:    with open("test_results.csv") as f:        for row in csv.DictReader(f):            outcome = "PASS" if row["Result"] == "PASS" else "FAIL"            tested_at = datetime.strptime(row["Date"], "%Y-%m-%d").replace(                tzinfo=timezone.utc            )            client.runs.create(                procedure_id=PROCEDURE_ID,                serial_number=row["Serial Number"],                part_number="PCB-V1",                outcome=outcome,                started_at=tested_at,                ended_at=tested_at,                phases=[{                    "name": "Power Supply Check",                    "outcome": outcome,                    "started_at": tested_at,                    "ended_at": tested_at,                    "measurements": [                        {                            "name": "Output Voltage",                            "measured_value": float(row["Voltage (V)"]),                            "units": "V",                            "validators": [                                {"operator": ">=", "expected_value": 3.1},                                {"operator": "<=", "expected_value": 3.5},                            ],                        },                        {                            "name": "Supply Current",                            "measured_value": float(row["Current (A)"]),                            "units": "A",                            "validators": [                                {"operator": "<=", "expected_value": 0.7},                            ],                        },                    ],                }],            )

Les limites deviennent des validators sur la mesure, ce qui rend les lignes historiques interprétables plus tard. Exécutez le script une fois pour reprendre l'historique, puis pointez les nouveaux tests vers la plateforme. Des importeurs existent aussi pour TestStand, STDF et d'autres formats.

Testez le script sur quelques lignes avant de traiter tout le fichier, et gardez le CSV d'origine jusqu'à avoir vérifié que le rendement importé correspond.

Migrer sans risque

Pas besoin de tout basculer d'un coup :

  1. Choisissez une station et ajoutez l'intégration à ses tests.
  2. Faites tourner les deux systèmes une semaine. Gardez le tableur pendant que la plateforme collecte les mêmes données.
  3. Comparez les rendements sur les mêmes unités. En cas d'écart, la raison vous apprend souvent quelque chose sur votre modèle de données, le plus souvent que le tableur comptait n'importe quel run réussi plutôt que le premier par unité.
  4. Déployez sur les stations restantes une fois les chiffres concordants.

Le tableur reste en sauvegarde jusqu'à ce que vous soyez prêt à le retirer.

Ce qu'il faut exiger, quel que soit le choix

Stockez la valeur mesurée, pas seulement le pass/fail. Un booléen dit qu'une unité a échoué. La valeur dit qu'elle dérivait depuis trois semaines.

Stockez les limites avec la valeur. Sinon les anciens résultats deviennent ininterprétables au premier changement de limite.

Versionnez la procédure de test. Même raison, et c'est quasi impossible à rattraper.

Modélisez les sous-ensembles dès le premier jour. Reconstruire après coup quelle carte est allée dans quel assemblage implique de lire des dossiers à la main.

Ces quatre décisions coûtent bien moins cher au départ qu'ajoutées plus tard, où que finissent les données.

Plus de guides

Mettez ce guide en pratique