Concepts & Methodology

Framework de test Python pour le matériel

La plupart des frameworks Python testent du code, pas des appareils. Voici ce qui fonctionne réellement pour le test en production, et dans quels cas.

JJulien Buteau
beginner9 min de lecture7 septembre 2026

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

BesoinPourquoi les frameworks unitaires ne l'ont pas
Mesures comme donnéesUn assert jette la valeur. Il vous faut le nombre, ses unités et ses limites, stockés
Identité par numéro de sérieLes tests unitaires n'ont aucune notion de l'objet physique testé
Interaction opérateurQuelqu'un doit scanner un code-barres, appuyer sur un bouton, confirmer la fermeture d'un montage
Cycle de vie des instrumentsUn 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 échecUn test unitaire s'arrête. Un test de production continue souvent pour collecter plus de diagnostic
Destination des résultatsLes 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.

test_power_rail.py
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.

functional_test.py
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.

procedure.yaml
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.4
phases/power_rail.py
def power_rail(measurements, multimeter):    measurements.rail_3v3 = multimeter.read_voltage()
plugs/dmm.py
class Multimeter:    def read_voltage(self) -> float:        return 3.31

Les 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

pytestOpenHTFFramework TofuPilot
Conçu pourTest logicielTest matérielTest matériel
MesuresImplicites dans les assertsStructurées avec limitesStructurées avec limites
Limites déclarées dansLes expressions assertDes décorateurs PythonLe YAML de procédure
Invite numéro de sérieManuelleIntégréeIntégrée
Interface opérateurAucuneInterface web basiqueConstruite depuis la procédure
Phases parallèlesVia xdistLimitéesNatives
Emplacements multiplesManuelsLimitésNatifs
Déploiement sur stationsÀ votre chargeÀ votre chargePush Git
Gestion hors ligneÀ votre chargeÀ votre chargeFile d'attente et sync
LicenceMITApache 2.0MIT

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.

Plus de guides

Mettez ce guide en pratique