web-dev-qa-db-fra.com

Pourquoi python le faux patch ne fonctionne pas?

J'ai deux fichiers

spike.py

class T1(object):
    def foo(self, afd):
        return "foo"

    def get_foo(self):
        return self.foo(1)


def bar():
    return "bar"

test_spike.py:

from unittest import TestCase
import unittest
from mock import patch, MagicMock
from spike import T1, bar


class TestStuff(TestCase):
    @patch('spike.T1.foo', MagicMock(return_value='patched'))
    def test_foo(self):
        foo = T1().get_foo()
        self.assertEqual('patched', foo)

    @patch('spike.bar')
    def test_bar(self, mock_obj):
        mock_obj.return_value = 'patched'
        bar = bar()
        self.assertEqual('patched', bar)


if __name__ == "__main__":
    unittest.main()

Quand je lance python test_spike.py, le premier cas de test réussirait, mais le second échouerait. et je passe à utiliser nosetests test_spike.py, puis les deux échouent.

Je ne comprends pas comment cela s'est produit? Ces cas censés passer tout.

24
LeoShi

Pour test_foo vous n'utilisez pas correctement le patch. Vous devriez l'utiliser comme ceci:

class TestFoo(TestCase):
@patch.object(T1, 'foo', MagicMock(return_value='patched'))
def test_foo(self):
    foo = T1().get_foo()
    self.assertEqual('patched', foo)

cela me donne:

nosetests test_spike.py 
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Maintenant, le deuxième exemple ne fonctionne pas, car vous importez la fonction de barre (obtenez une référence à celle-ci), puis essayez de vous en moquer. Lorsque vous vous moquez de quelque chose, vous ne pouvez pas modifier le contenu de vos variables (référence à la fonction d'origine). Pour résoudre ce problème, vous devez utiliser la méthode suggérée @falsetru comme:

from unittest import TestCase
import unittest
from mock import patch
import spike


class TestFoo(TestCase):
    @patch('spike.bar')
    def test_bar(self, mock_obj):
        mock_obj.return_value = 'patched'
        value = spike.bar()
        self.assertEqual('patched', value)


if __name__ == "__main__":
    unittest.main()

cela me donne:

python test_spike.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

Mais quand j'essaie de le faire avec le nez, je reçois:

 nosetests test_spike.py
F
======================================================================
FAIL: test_bar (src.test_spike.TestFoo)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/zilva/envs/test/local/lib/python2.7/site-packages/mock/mock.py", line 1305, in patched
    return func(*args, **keywargs)
  File "/home/zilva/git/test/src/test_spike.py", line 11, in test_bar
    self.assertEqual('patched', value)
AssertionError: 'patched' != 'bar'

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)

Cela arrive parce que je ne corrige pas au bon endroit. Ma structure de répertoire est:

test/
└── src/
    ├── spike.py
    ├── test_spike.py
    └── __init__.py

et je lance des tests à partir du répertoire src donc je devrais patcher en utilisant le chemin du répertoire racine du projet comme:

@patch('src.spike.bar')

et cela me donnerait:

nosetests test_spike.py
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

ou si je suis dans le répertoire de test:

nosetests src/test_spike.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s

OK
17

Accédez à bar à l'aide de spike.bar. bar importé n'est pas affecté par mock.patch.

from unittest import TestCase
import unittest
from mock import patch, MagicMock
from spike import T1
import spike # <----


class TestShit(TestCase):
    @patch('spike.T1.foo', MagicMock(return_value='patched'))
    def test_foo(self):
        foo = T1().get_foo()
        self.assertEqual('patched', foo)

    @patch('spike.bar')
    def test_bar(self, mock_obj):
        mock_obj.return_value = 'patched'
        bar = spike.bar() # <-----
        self.assertEqual('patched', bar)


if __name__ == "__main__":
    unittest.main()
21
falsetru