2017-08-08 2 views
1

Existe-t-il un moyen de spécifier un paramètre pytest.mark.parametrize() pour pytest, afin que les paramètres ne soient générés dynamiquement que si le test est sélectionné pour être exécuté?Comment utiliser un callable comme paramètre pytest parametrize()?

J'ai quelques opérations coûteuses à effectuer pour générer les paramètres, et je ne veux les exécuter que si le test est sélectionné pour être exécuté.

par exemple,

import pytest 

def my_callable(): 
    # do expensive operations here 
    return [(1, 2), (3, 6)] 


# I want my_callable to be called only if test_something 
# has been selected to be run 
@pytest.mark.parametrize("my_parm_1,my_parm_2", my_callable) 
def test_something(my_parm_1, my_parm_2): 
    assert my_parm_1 * 2 == my_parm_2 
+0

Tout cela ressemble à une petite déficience du côté pyêt. Peut-être vaut-il mieux envisager de déposer un bug avec pytest afin de reporter l'évaluation des paramètres au moment où les tests décorés sont exécutés (ou ajouter un paramètre decorator qui fait cela) ... – sophros

Répondre

0

Au lieu d'utiliser directement mycallable dans @pytest.mark.parametrize vous pouvez créer un proxy:

def my_callable(): 
    # do expensive operations here 
    return [(1, 2), (3, 6)] 

expensive_params = [paramset for paramset in my_callable()] 

@pytest.mark.parametrize("my_parm_1,my_parm_2", expensive_params) 
... 
+0

Fonctionne avec Python 3.6.1 et pytest 3.2 .0 – sophros

+1

Mais qu'en est-il de "et je veux seulement les exécuter si le test est sélectionné pour être exécuté"? Le 'expensive_params' est la variable globale qui sera toujours évaluée, même si le test n'est pas sélectionné, n'est-ce pas? –

+0

D'accord. 'expensive_params' est toujours évalué au moment de la compilation, alors que je veux qu'il soit évalué seulement si/quand le test est exécuté. –

0

Je pense que cela fait ce que vous voulez - le calcul coûteux est à l'intérieur du dispositif qui n'est invoqué que si le test est appelé et que le calcul coûteux n'est effectué qu'une seule fois:

class TestSomething: 

    _result = None 

    @pytest.fixture() 
    def my_callable(self): 
     if TestSomething._result is None: 
      # do expensive operations here 
      TestSomething._result = [(1, 2), (3, 6)] 

     def _my_callable(run_number): 
      return TestSomething._result[run_number] 
     return _my_callable 

    @pytest.mark.parametrize("run_number", [0, 1]) 
    def test_something(self, run_number, my_callable): 
     my_param_1, my_param_2 = my_callable(run_number) 
     assert my_param_1 * 2 == my_param_2 
+0

Bien que cela déplace les opérations coûteuses au moment de l'exécution du test, cela force également le code à connaître la longueur de l'itérative renvoyée par my_callable() à l'avance. Malheureusement, je ne connais pas la longueur de l'itérable à l'avance - les opérations coûteuses déterminent dynamiquement la longueur de l'itérable. Solution intéressante, mais elle ne répond pas tout à fait à mes exigences. De plus, cette solution n'a pas l'avantage de voir les valeurs des paramètres dans les noms des tests lorsqu'ils sont exécutés avec 'pytest -v'; seul le "numéro_exécution" serait vu. –

+0

@RobBednark en tenant compte du fait que le nombre de paramètres n'est pas connu, la seule autre chose qui vient à l'esprit est de supprimer 'parametrize', d'utiliser le dispositif comme ci-dessus et d'avoir une boucle sur des groupes de paramètres dans le code de test. Un peu moche, mais ça va marcher. –

+0

Oui, j'ai considéré boucler sur les paramètres à l'intérieur d'un seul test. J'espérais obtenir une solution de 'parametrize' où chaque ensemble de paramètres serait son propre test, plutôt que de les regrouper en un seul test. –