Si vous avez cherché un framework de test Python pour le matériel, vous avez sans doute remarqué le problème : presque tout ce que vous trouvez est conçu pour tester du code Python, pas pour tester un appareil physique sur un banc ou une ligne de production.
La distinction compte. Un test unitaire vérifie qu'une fonction renvoie la bonne valeur. Un test de production mesure une tension sur une carte réelle, la compare à une limite, enregistre le nombre, et indique à l'opérateur s'il doit placer l'unité dans le bac conforme ou non conforme. Ce sont deux métiers différents, et la plupart des frameworks ne font que le premier.
Voici les options qui existent réellement, et où chacune s'arrête.
Ce dont le test matériel a besoin et que le test unitaire n'offre pas
| Besoin | Pourquoi les frameworks unitaires ne l'ont pas |
|---|---|
| Mesures comme données | Un assert jette la valeur. Il vous faut le nombre, ses unités et ses limites, stockés |
| Identité par numéro de série | Les tests unitaires n'ont aucune notion de l'objet physique testé |
| Interaction opérateur | Quelqu'un doit scanner un code-barres, appuyer sur un bouton, confirmer la fermeture d'un montage |
| Cycle de vie des instruments | Un multimètre s'ouvre une fois, se partage entre étapes, et se ferme même en cas d'échec |
| Phases ordonnées avec poursuite après échec | Un test unitaire s'arrête. Un test de production continue souvent pour collecter plus de diagnostic |
| Destination des résultats | Les tests unitaires affichent dans un terminal. Les résultats de production doivent survivre à l'équipe |
Le dernier point est sous-estimé. Un test qui affiche « PASS » dans une console ne vous apprend rien six mois plus tard quand un client retourne une unité et que vous voulez savoir ce que mesurait sa tension de rail le jour de l'expédition.
Option 1 : pytest
pytest est le framework de test Python par défaut et le premier réflexe de la plupart des ingénieurs. Il fonctionne pour le matériel, avec des réserves.
import pytest@pytest.fixture(scope="session")def dmm(): import pyvisa rm = pyvisa.ResourceManager() inst = rm.open_resource("USB0::0x2A8D::0x1601::MY60012345::INSTR") yield inst inst.close()def test_rail_3v3(dmm): voltage = float(dmm.query("MEAS:VOLT:DC?")) assert 3.2 <= voltage <= 3.4, f"Rail 3.3V hors plage : {voltage}V"Ce qui marche. Les fixtures gèrent bien le cycle de vie des instruments, ce qui est la bonne abstraction pour un multimètre ou une alimentation. L'écosystème de plugins est énorme. Tout développeur Python le connaît déjà. Il tourne en CI sans modification.
Où ça s'arrête. La valeur mesurée vit dans un assert puis disparaît. Vous savez que le test a échoué ; vous n'avez pas la trace que le rail mesurait 3,19 V et dérivait depuis trois semaines. Pas de numéro de série, pas d'invite opérateur, pas d'interface pour un technicien. Vous finissez par écrire tout cela vous-même.
À utiliser quand vous faites de la validation R&D ou de la CI firmware, et que les résultats servent à un développeur plutôt qu'à une ligne de production.
Option 2 : OpenHTF
OpenHTF est un framework Python que Google a construit spécifiquement pour le test matériel. C'est ce qui se rapproche le plus d'une réponse dédiée, et c'est gratuit.
import openhtf as htffrom openhtf.util import unitsfrom openhtf.plugs import user_input@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) test.execute(test_start=user_input.prompt_for_test_start())if __name__ == "__main__": main()Ce qui marche. Les mesures sont des objets de première classe avec nom, valeur, unités et limites. Le pass/fail est évalué automatiquement depuis les limites. L'invite de numéro de série est intégrée. Les plugs gèrent le setup et le teardown des instruments. Une interface web basique existe pour les opérateurs.
Où ça s'arrête. Le test parallèle de plusieurs unités est limité. Le projet n'est plus activement développé par Google et la communauté est restreinte. Construire une vraie interface opérateur demande du travail frontend.
À utiliser quand vous faites du test fonctionnel de production en Python et voulez des mesures structurées sans concevoir de modèle de données.
Option 3 : le framework TofuPilot
Nous l'avons construit parce qu'OpenHTF a le bon modèle de données mais s'arrête sur tout le reste. Il est open source sous licence MIT.
Une procédure est un fichier .yaml qui déclare la séquence, les mesures et leurs limites. Les phases sont de simples fonctions Python sans décorateur, et les plugs connectent les instruments sous forme de classes Python.
name: Test fonctionnel PCBAunit: serial_number: default_value: "PCBA000001" part_number: default_value: "PCBA-200"plugs: - name: Multimeter python: plugs.dmm:Multimetermain: - 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, multimeter): measurements.rail_3v3 = multimeter.read_voltage()class Multimeter: def read_voltage(self) -> float: return 3.31Les limites vivent dans le YAML, donc la phase reste une fonction simple qui affecte une valeur. TofuPilot génère la clé de mesure depuis le nom en snake_case (Rail 3V3 devient rail_3v3), et injecte les plugs dans la phase selon la même règle.
Ce qu'il ajoute à OpenHTF. Les interfaces opérateur sont construites depuis la définition de procédure, avec saisies texte, listes de contrôle, images, curseurs et barres de progression, sans travail frontend. Les phases et les emplacements multiples s'exécutent en parallèle sur un moteur Rust pendant que votre code reste du Python simple. Les procédures se déploient sur les stations depuis un push Git, avec artefacts immuables et rollback instantané. Les runs se mettent en file d'attente hors ligne et se synchronisent au retour du réseau.
Où ça s'arrête. Plus récent qu'OpenHTF, donc communauté plus petite. Si votre équipe n'écrit pas de Python, aucune des options Python n'est la bonne réponse.
Option 4 : garder votre propre framework
Beaucoup d'équipes ont un framework Python maison qui fonctionne. Si c'est votre cas, le conseil honnête est d'être prudent avant de le remplacer.
Votre framework a été façonné autour de vos produits, de votre schéma de numéros de série et de votre structure de sous-ensembles. Les alternatives vous demandent de les plier à leur modèle, et c'est là que les migrations échouent.
Gardez-le quand il convient et que la seule plainte est la charge de maintenance plutôt qu'une capacité manquante.
Remplacez-le quand la maintenance concerne en réalité la couche d'analyse plutôt que l'exécution des tests. Rendement, capabilité, cartes de contrôle et traçabilité sont chacun un petit projet, et ensemble ils constituent ce que personne n'a le temps de maintenir.
Comparaison
| pytest | OpenHTF | Framework TofuPilot | |
|---|---|---|---|
| Conçu pour | Test logiciel | Test matériel | Test matériel |
| Mesures | Implicites dans les asserts | Structurées avec limites | Structurées avec limites |
| Limites déclarées dans | Les expressions assert | Des décorateurs Python | Le YAML de procédure |
| Invite numéro de série | Manuelle | Intégrée | Intégrée |
| Interface opérateur | Aucune | Interface web basique | Construite depuis la procédure |
| Phases parallèles | Via xdist | Limitées | Natives |
| Emplacements multiples | Manuels | Limités | Natifs |
| Déploiement sur stations | À votre charge | À votre charge | Push Git |
| Gestion hors ligne | À votre charge | À votre charge | File d'attente et sync |
| Licence | MIT | Apache 2.0 | MIT |
Choisir
Validation R&D ou CI firmware ? pytest. L'écosystème et la familiarité l'emportent sur les fonctions matérielles manquantes.
Test de production avec données structurées sans construire de schéma ? OpenHTF ou le framework TofuPilot.
Test de production sur plusieurs stations où les opérateurs ont besoin d'une interface et les scripts doivent atteindre les stations de façon fiable ? C'est ce pour quoi le framework TofuPilot a été construit.
Vous avez déjà quelque chose qui marche ? Réglez le problème de maintenance avant de remplacer le framework.
Où vont les résultats
Quel que soit le framework, décidez tôt où les résultats sont stockés. Un framework exécute des tests ; il ne répond pas à « quel était notre rendement la semaine dernière » ni à « quelle étape de test nous coûte le plus d'unités ».
Stockez la valeur mesurée, pas seulement le pass/fail. Versionnez la procédure pour que les résultats antérieurs à un changement de limite restent interprétables. Modélisez les sous-ensembles dès le premier jour même sans les utiliser. Ces trois décisions sont bien plus difficiles à rattraper qu'à prendre au départ.