web-dev-qa-db-ja.com

pythonモックパッチが機能しないのはなぜですか?

2つのファイルがあります

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()

python test_spike.pyを実行すると、最初のテストケースはパスしますが、2番目のテストケースは失敗します。 nosetests test_spike.pyを使用するように切り替えると、2つとも失敗します。

どうしてこうなったのか分かりませんか?これらのケースはすべて通過するはずです。

24
LeoShi

test_fooの場合、パッチは正しく使用されていません。次のように使用する必要があります。

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

それは私に与えます:

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

OK

ここで、2番目の例は、bar関数をインポートし(それへの参照を取得)、それをモックしようとしているため機能しません。何かをあざけるとき、変数が保持するものを変更することはできません(元の関数への参照)。これを修正するには、次のような@falsetruの推奨方法を使用する必要があります。

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()

これは私に与えます:

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

OK

しかし、それを鼻で実行しようとすると、次のようになります。

 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)

これは、適切な場所にパッチを適用していないために起こります。私のディレクトリ構造は:

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

私はsrcディレクトリからテストを実行するので、次のようにプロジェクトのルートディレクトリからのパスを使用してパッチを適用する必要があります。

@patch('src.spike.bar')

そしてこれは私に与えるでしょう:

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

OK

または私がテストディレクトリにいる場合:

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

OK
17

spike.barを使用してbarにアクセスします。インポートされたbarmock.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