Test Data & Analytics

Quoi enregistrer dans un test de production

Les champs à enregistrer dans un test de production pour que les échecs restent débogables six mois plus tard, et les quatre difficiles à ajouter après coup.

JJulien Buteau
beginner8 min de lecture7 septembre 2026

La plupart des systèmes d'enregistrement en production sont conçus pour l'instant où le test s'exécute. Un opérateur a besoin d'un feu vert ou rouge, le test l'affiche, et la réflexion s'arrête là.

Le problème arrive des mois plus tard. Un client retourne une unité. Une enquête de rendement a besoin d'une référence. Un auditeur demande ce qu'a mesuré un numéro de série précis. À ce moment, tout le monde veut exactement les données que personne n'a enregistrées.

Ce guide liste quoi enregistrer, par ordre de priorité, et signale les champs pénibles à rattraper.

Le minimum qui rend les données utiles

La valeur mesurée, pas seulement le pass/fail.

C'est le champ le plus précieux et le plus souvent oublié. Un booléen dit qu'une unité a échoué. La valeur dit qu'elle mesurait 3,19 V pour une limite à 3,20 V, et qu'elle baissait depuis trois semaines.

Tout en dépend. Courbes de tendance, capabilité, détection de dérive et ajustement des limites sont impossibles à partir de booléens. Si vous n'enregistrez qu'une chose au-delà du verdict, enregistrez le nombre.

Les limites appliquées.

Stockez les limites avec la valeur, pas seulement dans le code de test. Les limites changent, et un résultat enregistré sous les anciennes devient ininterprétable si elles ne l'accompagnent pas.

measurement.json
{  "name": "rail_3v3",  "value": 3.31,  "unit": "V",  "lower_limit": 3.2,  "upper_limit": 3.4,  "passed": true}

Les unités. Peu coûteux, et cela évite la classe d'erreurs où quelqu'un suppose ensuite des millivolts.

Un horodatage, en UTC. Stockez en UTC et convertissez à l'affichage. Sinon deux sites dans deux fuseaux ne s'accorderont pas sur le jour d'une défaillance.

Identité : ce qui a été testé

Numéro de série. Sans lui vous avez des statistiques mais aucune traçabilité.

Référence et révision. Une mesure ne signifie pas la même chose en rev C qu'en rev A. Sans la révision, des données de révisions mélangées se fondent silencieusement en une seule distribution.

Liens de sous-ensembles. Quelle carte dans quel boîtier, quel module dans quel assemblage final. C'est le champ le plus souvent omis et le plus pénible à ajouter après coup, car le rattraper implique de reconstruire des relations jamais capturées.

Modélisez-le dès le premier jour même sans l'utiliser. Quand un lot de composants s'avère défectueux, c'est ce qui vous dit quelles unités expédiées le contiennent.

Contexte : où et comment le test a eu lieu

Ces champs ne coûtent rien au moment du test et sont les dimensions de segmentation d'une enquête.

ChampCe qu'il permet de répondre
Identifiant de stationUne station échoue-t-elle plus que les autres ?
OpérateurUne technique de mise en place cause-t-elle des échecs ?
Version de procédureQuelle version des limites a produit ce résultat ?
Version de firmware du DUTUne constante de calibration a-t-elle changé ?
Identifiant de montageUn montage précis s'use-t-il ?
Instrument utiliséSi un multimètre était décalibré, quelles unités a-t-il touchées ?

L'identifiant de station se rentabilise le plus vite. Une seule requête groupant les échecs par station résout une part surprenante des enquêtes, et elle est impossible sans ce champ.

La version de procédure est l'autre à imposer. Les limites évoluent sur la vie d'un produit. Sans savoir quelle version a produit un résultat, vos données historiques cessent d'être comparables à chaque changement.

Détail d'exécution

Verdicts et durées par étape. Un run en échec en dit moins qu'un run échouant à l'étape 7 après avoir passé 1 à 6. Le niveau étape rend possible l'analyse de Pareto, et les durées révèlent une station qui ralentit.

Pièces jointes quand elles comptent. Une capture de forme d'onde, une photo d'unité en échec, une copie d'écran d'instrument. Pas sur chaque run en volume, mais sur les échecs.

Journaux du script de test. Sortie console, réponses d'instruments, traces d'exception. Peu coûteux sur les échecs, et c'est la différence entre diagnostiquer et deviner.

Ce qu'il ne faut pas enregistrer

La retenue compte, car un stockage qui grossit sans limite finit supprimé en bloc, généralement juste avant qu'on en ait besoin.

Formes d'onde brutes sur chaque unité. Stockez les caractéristiques extraites, temps de montée, dépassement, ondulation, et gardez la capture brute pour les échecs ou un échantillon.

Flux à haute cadence. Si vous acquérez à des centaines d'échantillons par seconde, agrégez avant de stocker. Une plateforme d'enregistrement sert aux résultats, pas à l'acquisition temporelle.

Ce qui est dérivable. Ne stockez pas le rendement comme champ. Calculez-le. Un agrégat stocké devient faux dès qu'un retest arrive.

Les quatre pénibles à rattraper

Tout ce qui précède peut s'ajouter plus tard avec un peu d'effort, sauf ceci :

  1. La valeur mesurée. Des booléens historiques ne redeviennent pas des nombres. Chaque jour sans cela est un jour de données irrécupérables.
  2. Les relations de sous-ensembles. Les reconstruire après coup implique de lire des dossiers de fabrication à la main, s'ils existent.
  3. Le versionnage de procédure. Une fois les limites changées sans marqueur de version, impossible de dire quels résultats sont comparables.
  4. Les numéros de série des premières unités. Prototypes et présérie sautent souvent la sérialisation, et ce sont précisément les unités qui reviennent avec les défaillances les plus intéressantes.

Un schéma minimal

Si vous stockez dans votre propre base, ceci couvre les champs ci-dessus :

schema.sql
CREATE TABLE unit (    id            BIGSERIAL PRIMARY KEY,    serial_number TEXT NOT NULL UNIQUE,    part_number   TEXT NOT NULL,    revision      TEXT,    parent_id     BIGINT REFERENCES unit(id),    created_at    TIMESTAMPTZ NOT NULL DEFAULT now());CREATE TABLE run (    id                BIGSERIAL PRIMARY KEY,    unit_id           BIGINT NOT NULL REFERENCES unit(id),    procedure_id      TEXT NOT NULL,    procedure_version TEXT NOT NULL,    station_id        TEXT NOT NULL,    operator          TEXT,    dut_firmware      TEXT,    started_at        TIMESTAMPTZ NOT NULL,    duration_s        NUMERIC NOT NULL,    passed            BOOLEAN NOT NULL);CREATE TABLE step (    id         BIGSERIAL PRIMARY KEY,    run_id     BIGINT NOT NULL REFERENCES run(id) ON DELETE CASCADE,    name       TEXT NOT NULL,    duration_s NUMERIC,    passed     BOOLEAN NOT NULL);CREATE TABLE measurement (    id          BIGSERIAL PRIMARY KEY,    step_id     BIGINT NOT NULL REFERENCES step(id) ON DELETE CASCADE,    name        TEXT NOT NULL,    value       DOUBLE PRECISION,    unit        TEXT,    lower_limit DOUBLE PRECISION,    upper_limit DOUBLE PRECISION,    passed      BOOLEAN NOT NULL);CREATE INDEX ON run (procedure_id, started_at DESC);CREATE INDEX ON run (station_id, started_at DESC);CREATE INDEX ON measurement (name, step_id);

Le parent_id sur unit est le lien de sous-ensemble. C'est une colonne, et l'ajouter maintenant coûte bien moins que reconstruire les relations plus tard.

Le faire sans écrire le schéma

Si vos scripts de test sont en Python, cette structure vient gratuitement. La définition de mesure dans votre code porte déjà le nom, la valeur, les unités et les limites, donc un callback de sortie enregistre tous les champs ci-dessus sans schéma de votre part.

Avec OpenHTF, c'est un import et une ligne :

main.py
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import upload@htf.measures(    htf.Measurement("rail_3v3")    .in_range(3.2, 3.4)    .with_units(units.VOLT),)def power_rail_test(test):    test.measurements.rail_3v3 = 3.31def main():    test = htf.Test(        power_rail_test,        procedure_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",  # UUID de procédure du dashboard        part_number="PCBA-200",    )    test.add_output_callbacks(upload())    test.execute(lambda: "SN-0001")if __name__ == "__main__":    main()

Installez-le avec pip install "tofupilot[openhtf]". Le callback upload() lit TOFUPILOT_API_KEY dans l'environnement, et add_output_callbacks est le point d'extension d'OpenHTF lui-même, donc il se compose avec vos callbacks existants.

Peu importe l'outil. Ce qui compte, c'est que la décision de ce qu'on enregistre se prend une fois, tôt, et coûte cher à revoir. Enregistrez la valeur, versionnez la procédure, modélisez les sous-ensembles, gardez l'UTC. Le reste peut attendre.

Plus de guides

Mettez ce guide en pratique