Migrating from Legacy Systems

Entretien d'ingénieur test : un exercice Python

Un exercice Python de deux heures qui vérifie le pilotage d'instrument, les limites et la gestion des pannes, avec fichiers de départ, grille et questions.

JJulien Buteau
intermediate9 min de lecture23 septembre 2026

Un exercice à faire chez soi pour un ingénieur test doit prouver quatre choses en moins de deux heures : le candidat sait dialoguer avec un instrument, appliquer des limites, gérer une panne matérielle, et livrer un résultat que quelqu'un d'autre peut lire. L'exercice ci-dessous le fait avec une alimentation simulée, un DMM simulé qui renvoie un timeout une fois sur dix, et le TofuPilot Framework comme séquenceur. Vous obtenez les fichiers de départ, une grille de notation et les questions pour la conversation qui suit.

Ce que l'exercice prouve

Un CV vous dit quels outils un candidat a utilisés. L'exercice vous dit s'il sait faire le travail, et il le fait en une heure de son temps et quinze minutes du vôtre.

CompétenceComment l'exercice la vérifie
Dialoguer avec un instrumentRégler une tension sur un plug d'alimentation, la relire via un plug DMM, tous deux avec une surface de méthodes réaliste.
Appliquer des limitesDéclarer les limites dans procedure.yaml, pas dans la phase. Savoir où vont les limites est le point clé.
Gérer une panne matérielleLe DMM simulé lève un timeout une fois sur dix. La phase doit réessayer ou échouer proprement, jamais se bloquer ni planter.
Livrer un résultatLe poste tourne avec tofupilot run et produit un run que quelqu'un d'autre peut ouvrir. Un bon candidat l'uploade et envoie le lien.

Les instruments sont simulés, donc le candidat n'a besoin de rien d'autre que Python et le CLI. C'est voulu : vous recrutez pour le raisonnement, et le vrai appel PyVISA est un remplacement d'une ligne qu'il fera la première semaine.

L'énoncé de l'exercice

Envoyez ceci comme README d'un petit dépôt avec les fichiers de départ ci-dessous. Demandez une pull request ou un zip sous une semaine, et dites que cela devrait prendre environ deux heures.

take-home/README.md
33 lines
# Exercice : phase de rail d'alimentationVous disposez d'un plug d'alimentation simulée et d'un plug de DMM simulé.Le DMM renvoie un timeout une fois sur dix. Écrivez une phase qui :1. Règle l'alimentation à 5,0 V et active la sortie.2. Relit la tension via le DMM.3. Enregistre la lecture comme mesure `rail_5v`, avec des limites   déclarées dans `procedure.yaml` (4,85 V à 5,15 V).4. Gère un timeout du DMM sans faire planter le run. Réessayer est   acceptable. Décidez combien de fois, et dites pourquoi dans un   commentaire.5. Coupe la sortie de l'alimentation à la fin, même quand quelque chose   échoue.Elle doit tourner avec :    curl -fsSL https://www.tofupilot.app/install | sh    tofupilot run ./procedure.yamlOptionnel : lancez-la avec `--upload` et envoyez-nous le lien du run depuishttps://tofupilot.app. L'offre Lab est gratuite et se configure en deuxminutes.Ce que nous regardons : où vivent les limites, comment le timeout est géré,si l'alimentation est toujours coupée, et si le code vous serait encoreclair dans six mois. Le nombre de lignes ne nous intéresse pas.Fichiers :- procedure.yaml       (squelette, complétez la phase et sa mesure)- phases/power_rail.py (ébauche)- plugs/mock_psu.py    (terminé, ne pas modifier)- plugs/mock_dmm.py    (terminé, ne pas modifier)

Gardez l'énoncé court. Un énoncé long teste la lecture, pas l'ingénierie.

Les fichiers de départ

Quatre fichiers. Les plugs sont complets et le candidat ne doit pas y toucher. La procédure et la phase sont des ébauches.

take-home/plugs/mock_psu.py
# Alimentation de paillasse simulée. Même surface de méthodes qu'un vrai plug d'alimentation SCPI.# STATE tient lieu du fil entre l'alimentation et le DMM.STATE = {"setpoint": 0.0, "output": False}class PowerSupply:    def __init__(self):        STATE["setpoint"] = 0.0        STATE["output"] = False    def set_voltage(self, volts: float) -> None:        STATE["setpoint"] = float(volts)    def output(self, enabled: bool) -> None:        STATE["output"] = bool(enabled)    def close(self) -> None:        STATE["output"] = False
take-home/plugs/mock_dmm.py
25 lines
# DMM simulé qui renvoie un timeout une fois sur N, comme une liaison GPIB ou LAN instable.import randomfrom plugs.mock_psu import STATEclass InstrumentTimeout(Exception):    """Levée quand l'instrument ne répond pas à temps."""class Multimeter:    TIMEOUT_ONE_IN = 10    def __init__(self):        # Un vrai plug ouvre ici une ressource VISA. Le mock lit le fil de l'alimentation.        self._rng = random.Random()    def read_voltage(self) -> float:        if self._rng.randrange(self.TIMEOUT_ONE_IN) == 0:            raise InstrumentTimeout("no reply from DMM within 2000 ms")        volts = STATE["setpoint"] if STATE["output"] else 0.0        return volts + self._rng.gauss(0.0, 0.01)    def close(self) -> None:        pass
take-home/procedure.yaml
20 lines
# Squelette. Ajoutez la phase sous main et sa mesure avec des limites.name: Take-home power railversion: 0.1.0unit:  serial_number:    default_value: TH-0001  part_number:    default_value: TAKE-HOME-Aplugs:  - name: psu    python: plugs.mock_psu:PowerSupply  - name: dmm    python: plugs.mock_dmm:Multimetermain:  - name: Power Rail    python: phases.power_rail    measurements: []
take-home/phases/power_rail.py
# Ébauche. Réglez 5 V sur l'alimentation, relisez-la sur le DMM, enregistrez rail_5v.# Gérez le timeout du DMM. Coupez toujours l'alimentation.def power_rail(measurements, psu, dmm):    raise NotImplementedError

Le DMM simulé lit le STATE de l'alimentation, donc une phase correcte relit environ 5 V et une phase qui a oublié d'activer la sortie obtient 0 V et une limite en échec. Dans un vrai poste, le plug DMM ouvre une ressource VISA à la place et ignore tout de l'existence d'une alimentation, ce qui est exactement la raison pour laquelle c'est la phase, pas le plug, qui est mise à l'épreuve.

La grille de notation

Notez chaque ligne avant la conversation, à partir du code seul. Trois lignes « fort » et aucune « faible », c'est une embauche au niveau intermédiaire.

CritèreFaibleSolideFort
LimitesCodées en dur dans la phase, ou un simple if avec un print.Déclarées dans procedure.yaml sous la mesure, la phase ne fait qu'enregistrer la valeur.Idem, et la description de la pull request dit d'où viennent 4,85 et 5,15 et demande si elles sont justes.
Gestion du timeoutNon attrapé, ou un except: nu qui avale tout.Attrape InstrumentTimeout, réessaie un nombre borné de fois, fait échouer la phase ensuite.Réessai borné avec une courte attente, le nombre d'essais est une constante nommée avec un commentaire sur le pourquoi, et le message d'échec dit ce que l'opérateur doit vérifier.
NettoyageAlimentation laissée allumée quand la phase échoue.Un try/finally coupe la sortie.Idem, et la phase ne va pas fouiller dans l'état privé du plug.
ExécutionNe tourne pas, ou demande des modifications pour tourner.tofupilot run ./procedure.yaml réussit et échoue comme prévu.L'a lancé avec --upload et a envoyé le lien du run depuis TofuPilot.
LisibilitéUne seule fonction qui fait tout, sans noms.De petites fonctions, des noms clairs, un commentaire là où il se justifie.Vous pourriez le confier à un junior et il le comprendrait sans poser de question.
CommunicationUn zip, sans note.Une courte note sur ce qu'il a fait et ce qu'il ferait ensuite.La note signale une vraie lacune de l'énoncé (temps de stabilisation avant la lecture, ce que « une fois sur dix » signifie pour le FPY).

Un « faible » en gestion du timeout ou en nettoyage est celui qui pèse le plus. Ces deux lignes sont ce qu'un poste fait à 2 h du matin quand personne ne regarde.

Les 45 minutes qui suivent

Parcourez son code pendant dix minutes, puis passez le reste sur ces questions. Il n'y a pas de bonne réponse ; vous écoutez comment il raisonne à propos d'un atelier.

« Que changeriez-vous pour tester 4 DUT à la fois ? » Solide : découper la phase par slot, une voie d'alimentation par DUT, garder les limites partagées. Fort : demande si le DMM est commuté par une matrice de relais ou s'il y a quatre DMM, et fait remarquer que le timeout coûte maintenant quatre unités de débit, pas une.

« D'où viennent 4,85 et 5,15 ? » Solide : la fiche technique du régulateur plus la marge de conception. Fort : demande ce que la charge en aval tolère, si le chiffre est le même à froid, et qui valide quand la limite change. Fait remarquer que la limite vit dans procedure.yaml, donc le changement est un diff relisible.

« Le Cpk de rail_5v passe de 1,6 à 1,1 en un mois. Que faites-vous ? » Solide : ouvrir la carte de contrôle dans TofuPilot, regarder si la moyenne a dérivé ou si la dispersion a augmenté, vérifier la date d'étalonnage du DMM. Fort : demande si c'est un poste ou tous, et si la résistance de contact du montage a changé avant d'accuser les cartes.

« Le DMM renvoie un timeout une fois sur dix. Quel effet sur le FPY ? » Solide : avec un réessai, aucun effet sur le FPY mais un effet sur le temps de cycle. Fort : dit qu'une liaison instable devrait donner un résultat en erreur, pas un échec, pour ne pas apparaître comme une perte de rendement, et demande comment la plateforme distingue les deux.

« Un opérateur dit que le poste a laissé passer une carte revenue morte de chez le client. Par où commencez-vous ? » Solide : ouvrir le run de ce numéro de série et lire les mesures. Fort : le compare à la population de cette phase, vérifie s'il est passé près d'une limite, et demande ce que le test ne couvre pas.

« Vous héritez d'un poste LabVIEW que personne ne peut ouvrir. À quoi ressemble votre première semaine ? » Écoutez : le faire tourner en tant qu'opérateur d'abord, trouver les limites, sortir les résultats de la machine, puis décider d'une réécriture. Bonus s'il a lu prise en main d'un ingénieur test en une semaine ou dit quelque chose d'approchant.

Notez la conversation avec la liste de compétences Python pour ingénieurs test pour que deux intervieweurs notent de la même façon.

Ce qu'il ne faut pas évaluer

N'évaluez pas une certification LabVIEW. CLAD, CLD et CLA prouvent que quelqu'un a réussi un examen NI, et l'examen couvre l'outil, pas l'atelier. Un candidat avec un CLD qui ne sait pas expliquer un réessai après timeout est une embauche plus faible qu'un candidat sans CLD qui le sait.

N'évaluez pas les noms de produits NI. Que quelqu'un ait utilisé un châssis PXI ou sache ce que signifie TDMS ne dit rien sur sa capacité à mettre en route un montage. Demandez comment il tirerait une mesure d'un instrument qu'il n'a jamais vu, et laissez-le choisir le fournisseur.

N'évaluez pas votre séquenceur. Si un candidat n'a utilisé qu'OpenHTF, pytest ou un runner maison, le TofuPilot Framework, c'est une journée de lecture. L'énoncé lui donne la structure ; l'exercice vérifie s'il l'utilise bien.

N'ajoutez pas d'épreuve d'algorithmique au tableau. Un ingénieur test trie par rendement, pas par nombre de comparaisons.

L'annonce qui produit des candidats pour cet exercice est dans fiche de poste d'ingénieur test pour recruter en Python.

Commencez par un poste

Avant d'envoyer l'exercice, faites-le vous-même. Mieux, construisez-le à partir d'un vrai poste : choisissez celui au plus gros volume ou celui qu'une seule personne peut ouvrir, reconstruisez-le en Python avec le TofuPilot Framework, faites-le tourner en parallèle de la version LabVIEW sur les mêmes unités pendant deux semaines, et taillez l'exercice dans l'une de ses phases. Les candidats résolvent alors un problème qui existe dans votre atelier, et les questions de suivi s'écrivent toutes seules.

install-and-run.sh
# Installe le CLI, puis lance le poste en local (sans compte) ou avec upload.curl -fsSL https://www.tofupilot.app/install | shtofupilot run ./procedure.yamltofupilot run ./procedure.yaml --upload

La reconstruction est dans comment migrer de LabVIEW vers Python pour les tests de fabrication avec TofuPilot, et le framework est sur tofupilot.com/products/framework. L'offre Lab est gratuite, et tofupilot run fonctionne sans compte.

Plus de guides

Mettez ce guide en pratique