Cinq frameworks dominent l'automatisation des tests de production : le framework TofuPilot, OpenHTF, pytest, OpenTAP et NI TestStand. Chacun fait des compromis différents entre structure, flexibilité, coût et écosystème. Ce guide les compare avec du code réel, des métriques concrètes et des critères de décision pour vous aider à choisir le bon.
Vue d'ensemble des frameworks
| Framework | Langage | Licence | Origine | Focus |
|---|---|---|---|---|
| Framework TofuPilot | Python (moteur Rust) | MIT (gratuit) | TofuPilot | Test de production avec exécution parallèle |
| OpenHTF | Python | Apache 2.0 (gratuit) | Test de fabrication/production | |
| pytest | Python | MIT (gratuit) | Communauté | Test logiciel, adapté au hardware |
| OpenTAP | C# / Python | MPL 2.0 (gratuit) | Keysight | Automatisation de test avec instruments |
| NI TestStand | LabVIEW / C / Python | Commercial (4 310 $/poste) | NI (Emerson) | Test de fabrication entreprise |
Matrice de comparaison des fonctionnalités
| Fonctionnalité | Framework TofuPilot | OpenHTF | pytest | OpenTAP | TestStand |
|---|---|---|---|---|---|
| Mesures structurées | Intégré (validators YAML) | Intégré (nom, valeur, limites, unités) | Manuel (assert uniquement) | Via plugins | Intégré |
| Saisie du numéro de série | Intégrée | Invite intégrée | Manuel | Plugin | Intégré |
| Interface opérateur | Déclarative, depuis la procédure | Interface web intégrée | Aucune | Intégrée (éditeur GUI) | Intégrée (Sequence Editor) |
| Séquencement des tests | Procédure YAML | Ordre des phases | Ordre des fonctions (plugins) | Ordre des étapes (GUI) | Fichiers de séquence (GUI) |
| Phases parallèles | Natives (moteur Rust) | Non | Via xdist | Natives | Natives |
| Bancs multi-slots | Natif | Limité | Manuel | Natif | Natif |
| Agrégations de waveforms | Intégrées (moyenne, min, max, écart-type) | Non | Manuel | Plugin | Manuel |
| Validators par axe | Intégrés | Non | Manuel | Non | Non |
| Pilotes d'instruments | Plugs (classes Python simples) | Plugs (Python) | Fixtures (Python) | Plugins (C#/Python) | Pilotes NI (LabVIEW) |
| Déploiement sur stations | Push Git, rollback instantané | À votre charge | À votre charge | Manuel | Manuel |
| Gestion hors ligne | File d'attente et sync | À votre charge | À votre charge | Manuel | Dépend de la base |
| Contrôle de version | Git (YAML + Python) | Git (fichiers Python) | Git (fichiers Python) | Git (XML + code) | Difficile (fichiers binaires .seq) |
| Intégration CI/CD | Native (Python) | Native (Python) | Native (Python) | Possible | Difficile |
| Multi-plateforme | Linux, macOS, Windows | Linux, macOS, Windows | Linux, macOS, Windows | Linux, Windows | Windows uniquement |
| Communauté | Récente, plus petite | Petite (~640 stars) | Massive (11K+ stars) | Petite (~200 stars) | Grande (forums NI) |
| Courbe d'apprentissage | Faible (YAML + Python simple) | Moyenne | Faible | Moyenne | Élevée |
| Coût annuel (5 postes) | 0 $ | 0 $ | 0 $ | 0 $ | ~21 550 $ |
Le même test dans chaque framework
Un test fonctionnel simple : mesurer une tension de rail 3,3 V, vérifier qu'elle est comprise entre 3,2 V et 3,4 V.
Framework TofuPilot
Le YAML de procédure déclare la séquence et les limites. Les phases sont des fonctions Python simples sans décorateur, et les plugs des classes Python simples.
procedure.yaml24 lines
name: PCBA Functional Testversion: 1.0.0unit: serial_number: default_value: "PCBA000001" part_number: default_value: "PCBA-100"plugs: - name: dut python: plugs.dut:Dutmain: - name: Power Rail Test python: phases.power_rail measurements: - name: Rail 3V3 unit: V validators: - operator: ">=" expected_value: 3.2 - operator: "<=" expected_value: 3.4def power_rail(measurements, dut): measurements.rail_3v3 = dut.read_voltage()class Dut: def read_voltage(self) -> float: return 3.31 # Remplacer par une lecture instrumentLancez-le depuis le dossier de la procédure avec tofupilot run.
Points forts : Les limites vivent dans le YAML comme des données, donc le plan de test est lisible et diffable séparément de la logique. Les phases et les slots de banc s'exécutent en parallèle sur un moteur Rust pendant que votre code reste du Python simple. L'interface opérateur est générée depuis la procédure sans travail frontend. Les procédures se déploient sur les stations via un push Git, avec rollback instantané, et les runs se mettent en file d'attente quand le réseau tombe.
Point faible : Plus récent qu'OpenHTF, donc communauté plus petite et moins d'exemples publics.
OpenHTF
comparison/openhtf_example.py29 lines
import openhtf as htffrom openhtf.util import unitsclass DutPlug(htf.plugs.BasePlug): def setUp(self): self.voltage = 3.31 # Remplacer par la lecture de l'instrument def tearDown(self): pass@htf.measures( htf.Measurement("rail_3v3") .in_range(3.2, 3.4) .with_units(units.VOLT),)@htf.plug(dut=DutPlug)def test_power(test, dut): test.measurements.rail_3v3 = dut.voltagedef main(): test = htf.Test(test_power, procedure_id="FCT-001", part_number="PCBA-100") test.execute(test_start=lambda: input("Numéro de série : "))if __name__ == "__main__": main()Points forts : Les mesures sont des données structurées (nom, valeur, limites, unités). Des années d'usage en production à grande échelle. L'invite de numéro de série est intégrée. S'exécute nativement sur le CLI TofuPilot sans code supplémentaire.
Point faible : Les phases s'exécutent en séquence sur une seule unité. Les phases parallèles et les bancs multi-slots s'orchestrent en dehors du framework.
pytest
import pytest@pytest.fixturedef dut(): connection = {"voltage": 3.31} # Remplacer par une vraie connexion yield connectiondef test_power_rail(dut): voltage = dut["voltage"] assert 3.2 <= voltage <= 3.4, f"Rail 3,3 V : {voltage} V"Points forts : Familier pour tout développeur Python. Énorme écosystème de plugins. Système de fixtures flexible. Excellent pour la R&D et la validation.
Point faible : Les mesures sont implicites (instructions assert). La valeur mesurée vit dans un assert puis disparaît, donc pas de données structurées pour l'analytique sans code supplémentaire.
OpenTAP
comparison/opentap_example.cs21 lines
// Étape de test OpenTAP en C#using OpenTap;[Display("Power Rail Test", Group: "FCT")]public class PowerRailStep : TestStep{ [Display("Lower Limit")] public double LowerLimit { get; set; } = 3.2; [Display("Upper Limit")] public double UpperLimit { get; set; } = 3.4; public override void Run() { double voltage = 3.31; // Remplacer par la lecture de l'instrument Results.Publish("rail_3v3", new { Voltage = voltage }); if (voltage < LowerLimit || voltage > UpperLimit) UpgradeVerdict(Verdict.Fail); }}Points forts : Éditeur d'étapes en GUI pour les non-programmeurs. Forte intégration avec les instruments Keysight. Architecture de plugins pour les plans de test.
Point faible : Langage principal en C# (le plugin Python existe mais est secondaire). Communauté plus restreinte.
NI TestStand
TestStand utilise un éditeur de séquences visuel. Le test équivalent est un fichier de séquence (.seq) avec une étape « Numeric Limit Test » configurée via l'interface : valeur de test = lecture de tension, limite basse = 3,2, limite haute = 3,4.
Points forts : Mature, qualité entreprise. Intégration poussée avec le hardware NI. Génération de rapports, journalisation en base de données, exécution parallèle intégrées.
Point faible : 4 310 $/poste/an. Windows uniquement. Les fichiers de séquence binaires ne se versionnent pas bien. Dépendance à l'écosystème NI.
Analyse des coûts
| Framework TofuPilot | OpenHTF | pytest | OpenTAP | TestStand | |
|---|---|---|---|---|---|
| Licence (5 postes) | 0 $ | 0 $ | 0 $ | 0 $ | 21 550 $/an |
| Licence (20 postes) | 0 $ | 0 $ | 0 $ | 0 $ | 86 200 $/an |
| Déploiement runtime | Gratuit | Gratuit | Gratuit | Gratuit | Licences runtime supplémentaires |
| Formation | Auto-formation (docs) | Auto-formation (docs) | Auto-formation (docs) | Auto-formation (docs) | Formations NI (2 000 $+) |
| Verrouillage fournisseur | Aucun (MIT, open source) | Aucun | Aucun | Faible (proche Keysight) | Élevé (écosystème NI) |
| Support | Communauté + TofuPilot | Communauté (GitHub) | Communauté (massive) | Communauté + Keysight | Contrat de support NI |
Quand utiliser chaque framework
| Scénario | Meilleur choix | Pourquoi |
|---|---|---|
| Test de production, ligne limitée par le débit | Framework TofuPilot | Phases parallèles et bancs multi-slots réduisent le temps de cycle |
| Test de production, opérateurs guidés | Framework TofuPilot | Interface opérateur déclarative, sans travail frontend |
| Validation de waveforms ou de sweeps | Framework TofuPilot | Agrégations et validators par axe vérifient la forme de la courbe |
| Nouvelles stations, plusieurs sites | Framework TofuPilot | Déploiement sur push Git, rollback instantané, file d'attente hors ligne |
| Suites OpenHTF déjà en production | OpenHTF | Tourne nativement sur le CLI TofuPilot ; le coût de migration n'en vaut pas la peine |
| Paradigme Python pur, sans couche YAML | OpenHTF | Tout en décorateurs Python |
| Validation R&D, CI firmware | pytest | Flexible, itération rapide, natif CI/CD, énorme écosystème |
| Instruments multi-fournisseurs, entreprise | OpenTAP | Architecture de plugins, éditeur GUI, intégration Keysight |
| Hardware NI existant, grande entreprise | TestStand | Intégration NI poussée, support entreprise, infrastructure existante |
| Mixte (R&D + production) | pytest + Framework TofuPilot | pytest pour la validation, Framework pour la production |
Parcours de migration
De TestStand vers le framework TofuPilot
| Concept TestStand | Équivalent framework TofuPilot |
|---|---|
| Fichier de séquence (.seq) | procedure.yaml |
| Types d'étapes | Fonctions de phase dans phases/ |
| Numeric Limit Test | measurements avec validators en YAML |
| String Value Test | validators avec operator: "==" |
| Module d'étape (code) | Classe de plug dans plugs/ |
| Process model | Intégré au CLI |
| Génération de rapports | Tableau de bord TofuPilot |
| Numéro de série UUT | unit.serial_number dans la procédure |
| Exécution de séquences en parallèle | execution.slots |
D'OpenHTF vers le framework TofuPilot
| Concept OpenHTF | Équivalent framework TofuPilot |
|---|---|
Fonction de phase avec @htf.measures | Fonction simple, mesures déclarées en YAML |
.in_range(3.2, 3.4) | validators avec >= et <= |
Sous-classe de BasePlug | Classe Python simple |
@htf.plug(dut=DutPlug) | Plug injecté par nom de paramètre |
test.measurements.x = v | measurements.x = v |
htf.Test(phase1, phase2) | Liste main: dans la procédure |
De pytest vers le framework TofuPilot
| Concept pytest | Équivalent framework TofuPilot |
|---|---|
| Fonction de test | Fonction de phase |
| Fixture | Plug |
| Instruction assert | validators dans le YAML de procédure |
| conftest.py | Dossier plugs/ |
| XML JUnit | Tableau de bord TofuPilot |
Intégration TofuPilot
Les cinq frameworks fonctionnent avec TofuPilot :
| Framework | Méthode d'intégration | Effort |
|---|---|---|
| Framework TofuPilot | Native (tofupilot run --upload) | Aucun |
| OpenHTF | Native sur le CLI TofuPilot | Aucun |
| pytest | SDK Python (TofuPilotClient) | ~10 lignes par test |
| OpenTAP | API REST ou SDK Python | Moyen |
| TestStand | API REST | Moyen |
Le framework TofuPilot et OpenHTF tournent tous deux nativement sur le CLI, qui streame phases, mesures, logs, pièces jointes et interface opérateur vers le dashboard sans code supplémentaire d'un côté comme de l'autre.
Arbre de décision
- Avez-vous une infrastructure TestStand existante ? Oui, et elle fonctionne bien : restez sur TestStand. Oui, mais vous souhaitez migrer : passez au framework TofuPilot.
- Utilisez-vous déjà OpenHTF en production ? Oui : gardez-le. Il tourne nativement sur le CLI TofuPilot, et le coût de migration n'en vaut pas la peine sauf si vous avez besoin de slots parallèles.
- Construisez-vous des tests de production sur de nouvelles stations ? Oui : le framework TofuPilot. Exécution parallèle, interface opérateur déclarative et déploiement sur push sont intégrés.
- Faites-vous de la R&D ou de la validation firmware ? Oui : pytest. Plus flexible, meilleur pour le CI/CD.
- Avez-vous besoin d'une interface graphique pour les non-programmeurs ? Oui : OpenTAP. Éditeur d'étapes visuel.
- Pas sûr ? Commencez par le framework TofuPilot.
tofupilot run ./procedure.yamlexécute une procédure sur votre machine sans compte.
Pour une comparaison plus poussée des deux options Python dédiées, voir Framework TofuPilot vs OpenHTF.
