Test Station Setup

Que sont les test sockets

Un test socket est une position de banc et le contexte qui possède son unité. Comment les sockets isolent les résultats et se configurent en slots.

JJulien Buteau
intermediate9 min de lecture9 septembre 2026

Que sont les test sockets et comment les utiliser

Un test socket est une position sur un banc qui accueille une unité sous test, avec le contexte logiciel qui la suit. Un banc à quatre positions a quatre sockets, et la test executive exécute quatre copies du test, une par socket, chacune avec sa propre unité, ses propres mesures et son propre résultat.

Le terme vient de NI TestStand, où les sockets sont le mécanisme derrière les modèles parallèle et batch. Le TofuPilot Framework appelle le même concept un slot. Ce guide explique ce que font les sockets, à quoi sert un identifiant de socket, et comment les configurer.

Pourquoi ce concept existe

Exécuter le même test sur quatre unités à la fois crée un problème d'identité. Quatre mesures de tension arrivent, et toutes s'appellent supply_voltage. Sans identité par position, impossible de dire quelle unité a échoué, quelle position de banc dérive, ou quel numéro de série attacher à un résultat.

Un socket résout cela en étant ce qui possède l'unité pendant la durée du test :

Un socket possèdeExemple
L'unité sous testNuméro de série SN-2024-003, en position 3
Ses voies d'instrumentVoie 3 du multimètre, sortie 3 de l'alimentation
Ses mesuresLa tension lue sur cette unité
Son verdictRéussite, indépendamment des autres positions
Son enregistrementUne exécution sur le tableau de bord

Quatre sockets, ce sont quatre contextes de test indépendants partageant un poste, une procédure et un opérateur.

Les sockets sont le mécanisme derrière l'exécution parallèle et batch ; pour choisir entre ces stratégies, voir Test séquentiel, parallèle ou batch.

L'identifiant de socket

Chaque socket porte un identifiant lisible par votre code de test. C'est la chose la plus importante qu'un socket apporte, car c'est ainsi qu'un test générique devient conscient de sa position.

Le problème résolu : votre code de phase est écrit une fois mais s'exécute N fois. Quelque chose doit indiquer à l'instance 3 de parler à la voie 3 de l'instrument. Ce quelque chose est l'identifiant de socket.

La plupart des phases n'en ont jamais besoin. Quand chaque socket a son propre instrument, le plug est de portée slot et la phase reste générique :

phases/measure_voltage.py
def measure_voltage(measurements, power_supply):    measurements.voltage = power_supply.read_voltage()

Quand une phase a besoin de connaître sa position — pour adresser une voie sur un instrument partagé, par exemple — elle lit run.slot_id, la clé déclarée dans execution.slots :

phases/measure_rail.py
CHANNELS = {"s1": 101, "s2": 102, "s3": 103, "s4": 104}def measure_rail(measurements, run, dmm):    measurements.rail_voltage = dmm.measure_dc_volts(CHANNELS[run.slot_id])

Gardez le câblage par socket dans la configuration et des tables de correspondance plutôt que de brancher sur la position à l'intérieur de la logique de test. C'est ce qui garde la procédure lisible quand le banc passe de quatre à quatre-vingts positions.

Configurer les sockets

Dans le TofuPilot Framework, les sockets se déclarent comme des slots sous execution :

procedure.yaml
execution:  slots:    - name: USB0    - name: USB1    - name: USB2    - name: USB3

Chaque entrée prend un name et un key optionnel, l'identifiant que voient les phases. Si la clé est omise, elle est dérivée du nom. Nommer les slots d'après la chose physique à laquelle ils correspondent — un port USB, un numéro de nid, une tête de sonde — est ce qui rend un rapport d'échec exploitable, parce que « USB2 a échoué 40 fois aujourd'hui » désigne du matériel.

Pour un banc avec de nombreuses positions identiques, donnez un nombre :

procedure.yaml
execution:  slots: 80

Le nombre se déploie en clés slot_01 à slot_80, complétées par des zéros pour que les positions se trient correctement partout. Le nombre est plafonné à 1024, et le moteur borne slots multipliés par phases à 10 000 travaux par exécution. Utilisez la forme liste quand les positions ont des noms significatifs.

Identification de l'unité par socket

Chaque socket identifie sa propre unité. Sur un poste où un opérateur scanne chaque position, l'invite d'unité apparaît par socket. Sur un rack où les numéros de série sont dérivés de la position, utilisez les substitutions {slot} et {slot_name} :

procedure.yaml
execution:  slots:    - key: s01      name: Nest 1    - key: s02      name: Nest 2unit:  auto_identify: true  serial_number:    default_value: "BURNIN-{slot}"  part_number:    default_value: "PCB-MAIN-V2"  batch_number:    default_value: "{slot_name}"

Avec auto_identify: true, le rack démarre sans aucune saisie opérateur. Sans cette option, la valeur déployée pré-remplit l'invite de chaque socket, ce qui est l'entre-deux utile : l'opérateur confirme au lieu de saisir.

Les procédures mono-slot ne voient jamais ces substitutions et les gardent comme texte littéral, donc les ajouter tôt ne casse pas un poste à une position.

Une exécution par socket

Chaque socket envoie sa propre exécution : son unité, ses phases plus les setup et teardown partagés, ses mesures, journaux, pièces jointes et son propre verdict.

Les exécutions d'un même démarrage partagent un execution_id, et chacune porte son slot_key et son slot_name. Cela donne deux vues des mêmes données :

  • Grouper par execution_id pour voir tout ce qui s'est passé dans un cycle.
  • Filtrer par slot_key pour voir une position de banc dans le temps.

La seconde vue est celle qui attrape une position défectueuse. Si le nid 3 échoue à 12 % pendant que les sept autres sont à 2 %, le problème est le banc, pas le produit — et aucune analyse de rendement agrégé ne l'aurait montré.

Ressources par socket et partagées

Les instruments sont attachés avec une portée qui décide du nombre d'instances :

PortéeInstanceÀ utiliser pour
slot (défaut)Une par socketVoie d'alimentation par position, port série par position
executionUne partagée par tous les socketsUn multimètre unique derrière un multiplexeur, une enceinte
stationUne par poste, conservée entre exécutionsConnexions VISA ou TCP lentes à ouvrir
procedure.yaml
plugs:  - name: power_supply    python: plugs.psu:PowerSupply    scope: slot  - name: chamber    python: plugs.chamber:ThermalChamber    scope: execution

Une instance de plug exécute un appel de méthode à la fois. Quand plusieurs sockets appellent le même plug execution ou station, les appels sont mis en file et exécutés un par un. C'est le principal piège de débit du test par sockets : une méthode d'instrument partagé qui prend deux secondes en coûte huit sur quatre sockets, et le parallélisme configuré n'existe discrètement plus. Gardez les méthodes de plug partagé courtes et mettez les longues attentes dans les phases. Partager des instruments entre slots parallèles traite ce point en détail.

Isolation des échecs

Les sockets échouent indépendamment. Une phase en échec sous le comportement stop par défaut, un phase.stop(), une erreur ou un timeout saute les phases restantes de ce socket et exécute son teardown de portée slot, pendant que les autres sockets continuent. Chaque socket a son propre verdict, et le verdict de l'exécution est le pire d'entre eux.

Seules trois choses arrêtent tous les sockets : un échec dans une phase partagée par tous (setup ou teardown avec scope: execution), un plug qui échoue à s'initialiser, ou l'opérateur qui arrête l'exécution.

D'où une règle qui mérite d'être énoncée clairement, car l'enfreindre produit des échecs intermittents très difficiles à diagnostiquer :

Un teardown de portée slot peut s'exécuter pendant que ses voisins testent encore. Tout ce qu'il touche doit appartenir à ce socket seul. Une alimentation de rack, une enceinte, un verrou de banc, un multiplexeur partagé appartiennent à une phase de teardown avec scope: execution, qui s'exécute une fois après la fin de tous les sockets.

procedure.yaml
teardown:  - name: Discharge This Position    python: phases.discharge  - name: Power Down Rack Supply    python: phases.rack_off    scope: execution

Si Power Down Rack Supply était de portée slot, le premier socket à terminer couperait l'alimentation de toutes les unités encore sous test. Le symptôme est une poignée d'échecs inexpliqués sur les positions les plus lentes, ce qui ressemble à un problème produit et n'en est pas un.

Pièges courants

Coder en dur une adresse d'instrument dans un plug de portée slot. Quatre sockets parlent alors à la même voie physique, et quatre unités rapportent les mesures de la première. Passez l'adresse par la configuration du plug de chaque socket.

Supposer que les sockets accélèrent un instrument partagé. Non. La mise en file d'attente sur un plug de portée execution sérialise ces appels par conception.

Nommer les sockets uniquement par index. slot_03 est plus difficile à exploiter que Nest 3 ou Sonde C. Les noms apparaissent dans chaque rapport d'échec.

Oublier qu'un échec de setup partagé arrête tout. Une enceinte qui n'atteint pas sa température interrompt correctement tous les sockets. C'est le comportement voulu, mais cela signifie que les phases de setup partagé méritent des reprises et des messages d'erreur clairs plus que les phases par socket.

Points clés

  • Un test socket est une position de banc plus le contexte logiciel qui possède son unité, ses mesures et son verdict.
  • L'identifiant de socket, lu depuis run.slot_id, est ce qui rend un test générique conscient de sa position.
  • Dans le TofuPilot Framework, les sockets sont execution.slots, et chacun envoie son exécution étiquetée avec slot_key et execution_id.
  • Filtrer les résultats par socket est la façon d'attraper une position de banc défectueuse que le rendement agrégé masque.
  • Les instruments partagés se sérialisent entre sockets, et les ressources partagées doivent utiliser scope: execution en teardown.

Plus de guides

Mettez ce guide en pratique