【问题标题】:Why python mock patch doesn't work?为什么python模拟补丁不起作用?
【发布时间】:2013-11-27 12:43:46
【问题描述】:

我有两个文件

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 时,第一个测试用例会通过,但第二个会失败。 我切换到使用nosetests test_spike.py,然后两个都失败了。

我不明白这是怎么回事?这些情况应该都通过了。

【问题讨论】:

标签: python unit-testing mocking nose


【解决方案1】:

使用spike.bar 访问bar。导入的bar 不受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()

【讨论】:

  • 谢谢,它适用于python test_spike.py,但为什么它仍然不适用于nosetests test_spike.py
  • @LeoShi,对不起,我不知道。
  • "导入的 bar 不受 mock.patch 影响" --> 这救了我的命!
【解决方案2】:

对于 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

现在第二个示例不起作用,因为您导入 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

【讨论】:

    【解决方案3】:

    为了详细说明非常有用的最佳答案,让我解释一下unittest.mock 的官方文档。

    a.py
        class SomeClass:
            ...
    
    b.py
        import a
        from a import SomeClass
        def some_function():
            a.SomeClass()
            SomeClass()
    

    如果你写mock.patch('a.SomeClass'),这会影响some_function的第一行。如果写mock.patch('b.SomeClass'),会影响第二行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-06-22
      • 2013-04-10
      • 1970-01-01
      • 2015-06-25
      • 2020-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多