2014-08-28 6 views
6

Je souhaite être capable de renvoyer une valeur d'un appareil à plusieurs tests/classes de test, mais la valeur transmise est une fonction.pytest fixture renvoie toujours une fonction

Voici mon code:

import pytest 

@pytest.fixture() 
def user_setup(): 
    user = { 
     'name': 'chad', 
     'id': 1 
    } 
    return user 

@pytest.mark.usefixtures('user_setup') 
class TestThings: 
    def test_user(self): 
     assert user_setup['name'] == 'chad' 

La sortie est:

=================================== FAILURES =================================== 
_____________________________ TestThings.test_user _____________________________ 

self = <tests.test_again.TestThings instance at 0x10aed6998> 

    def test_user(self): 
>  assert user_setup['name'] == 'chad' 
E  TypeError: 'function' object has no attribute '__getitem__' 

tests/test_again.py:14: TypeError 
=========================== 1 failed in 0.02 seconds =========================== 

Mais si je réécris mon test afin qu'il ne pas utiliser le décorateur usefixtures, il fonctionne comme prévu:

def test_user(user_setup): 
    assert user_setup['name'] == 'chad' 

Des idées pour lesquelles cela ne fonctionne pas lorsque j'essaie d'utiliser la méthode du décorateur?

Répondre

13

Lorsque vous utilisez le marqueur @pytest.mark.usefixtures vous devez toujours fournir un argument d'entrée du même nom si vous voulez que fixation à injecter dans à votre fonction de test.

Comme décrit dans les py.test docs for fixtures:

Le nom de la fonction de fixation peut ensuite être référencé pour provoquer son appel avant l'exécution des tests ... Fonctions de test peuvent utiliser directement noms de fixation comme arguments d'entrée dans Dans ce cas, l'instance de l'appareil renvoyée par la fonction d'appareil sera injectée.

Donc, simplement en utilisant le décorateur @pytest.mark.usefixtures invoquera seulement la fonction. Fournir un argument d'entrée vous donnera le résultat de cette fonction.

Vous n'avez vraiment besoin d'utiliser @pytest.mark.usefixtures que lorsque vous souhaitez appeler un appareil mais que vous ne voulez pas l'utiliser comme argument d'entrée pour votre test. Comme décrit dans le py.test docs.

La raison pour laquelle vous obtenez une anomalie qui fait référence à user_setup en raison d'une fonction est qu'à l'intérieur de votre test_user le nom user_setup fait référence à la fonction que vous avez définie précédemment dans le fichier. Pour obtenir votre code fonctionne comme prévu, vous devrez ajouter un argument à la fonction test_user:

@pytest.mark.usefixtures('user_setup') 
class TestThings: 
    def test_user(self, user_setup): 
     assert user_setup['name'] == 'chad' 

Maintenant, du point de vue de la fonction test_user le nom user_setup fera référence à l'argument de la fonction qui sera le retour valeur de l'appareil injecté par py.test.

Mais vous n'avez vraiment pas besoin d'utiliser le décorateur @pytest.mark.usefixtures.

+2

Merci pour l'explication claire sur comment cela fonctionne. Je pensais que je pourrais accomplir ceci sans devoir ajouter l'argument à chaque fonction de test qui est dans ma classe de test. – Cass

+0

Je cherchais juste la différence et/ou des cas d'utilisation pour ces deux variantes et quand utiliser quoi, merci pour cette explication. – Zelphir

+0

Selon les docs officiels, vous ne devriez pas * avoir * à ajouter 'user_setup' à chaque fonction de test quand ils sont groupés sous une classe décorée avec' @ pytest.mark.usefixtures': "En raison du marqueur" usefixtures ", le cleandir fixture sera nécessaire pour l'exécution de chaque méthode de test, comme si vous aviez spécifié un argument de fonction "cleandir" pour chacun d'entre eux. "(Source: http://pytest.org/latest/fixture.html#using-fixtures -from-classes-modules-or-projects) Après tout, le but de regrouper des tests comme celui-ci est de les manipuler comme un lot.) ... Peut-être que c'est un bug pyest? – Zearin

-1

Dans les deux cas, dans global la portée user_setup fait référence à la fonction. La différence est que, dans votre version nonfixture, vous créez un paramètre avec le même nom, ce qui est une recette classique pour la confusion.

Dans cette version de nonfixture, dans la portée de test_user, votre identificateur user_setup fait référence à ce que vous lui transmettez, PAS à la fonction dans la portée globale.

Je pense que vous voulez dire probablement être appeler user_setup et subscripting le résultat comme

assert user_setup()['name'] == 'chad'