我无法弄清楚如何在python中模拟我的函数,我已经尝试寻找一些代码,但似乎没有工作,考虑这个布局:
| project.py
| tests.py
project.py
:
def foobar():
return
tests.py
:
import unittest
from unittest.mock import patch
import os
from project import foobar
def os_urandom_mock():
return 'mocked'
def foobar_mock():
return 'mocked'
class TestProject(unittest.TestCase):
# mocked os.urandom worked well
@patch('os.urandom', side_effect=os_urandom_mock)
def test_os_urandom_mocked(self, os_urandom_mocked):
self.assertEqual(os.urandom(), 'mocked')
# but this doesn't
@patch('project.foobar', side_effect=foobar_mock)
def test_foobar_mocked(self, foobar_mocked):
self.assertEqual(foobar(), 'mocked')
# and this also doesn't work
@patch('project.foobar')
def test_foobar_mocked_another(self, foobar_mocked):
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
# and this also doesn't work
def test_foobar_mocked_last_try(self):
with patch('project.foobar') as foobar_mocked:
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
unittest.main()
所以,python3 tests.py
:
======================================================================
FAIL: test_foobar_mocked (__main__.TestProject)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python36\lib\unittest\mock.py", line 1179, in patched
return func(*args, **keywargs)
File "tests.py", line 24, in test_foobar_mocked
self.assertEqual(foobar(), 'mocked')
AssertionError: None != 'mocked'
======================================================================
FAIL: test_foobar_mocked_another (__main__.TestProject)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Python36\lib\unittest\mock.py", line 1179, in patched
return func(*args, **keywargs)
File "tests.py", line 30, in test_foobar_mocked_another
self.assertEqual(foobar(), 'mocked')
AssertionError: None != 'mocked'
======================================================================
FAIL: test_foobar_mocked_last_try (__main__.TestProject)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 35, in test_foobar_mocked_last_try
self.assertEqual(foobar(), 'mocked')
AssertionError: None != 'mocked'
----------------------------------------------------------------------
Ran 4 tests in 0.002s
FAILED (failures=3)
正如您所看到的test_os_urandom_mocked
没问题,但我尝试模仿我的foobar
功能的所有其他测试都失败了,不知道为什么,任何人都可以解释如果有可能吗?
答案 0 :(得分:3)
您可以通过模块参考补丁功能来完成这项工作:
import unittest
from unittest.mock import patch
import os
import project
def os_urandom_mock():
return 'mocked'
def foobar_mock():
return 'mocked'
class TestProject(unittest.TestCase):
@patch('os.urandom', side_effect=os_urandom_mock)
def test_os_urandom_mocked(self, os_urandom_mocked):
self.assertEqual(os.urandom(), 'mocked')
@patch('project.foobar', side_effect=foobar_mock)
def test_foobar_mocked(self, foobar_mocked):
self.assertEqual(project.foobar(), 'mocked')
@patch('project.foobar')
def test_foobar_mocked_another(self, foobar_mocked):
foobar_mocked.return_value = 'mocked'
self.assertEqual(project.foobar(), 'mocked')
def test_foobar_mocked_last_try(self):
with patch('project.foobar') as foobar_mocked:
foobar_mocked.return_value = 'mocked'
self.assertEqual(project.foobar(), 'mocked')
unittest.main()
这里要带走的关键是当你给patch
一个字符串时,它会替换该路径上的引用 。这种行为得到了很好的证明here。 (感谢wholevinski获取链接。)
使用现在的代码,测试文件中的foobar
引用原始函数,因为您在补丁到位之前导入了它。相比之下,如果您通过模块引用它,您将始终使用该模块的参考。
或者,您可以执行评论中建议的wholevinski,并让您的修补程序替换当前范围中的引用 而不是原始模块中的:
import unittest
from unittest.mock import patch
import os
from project import foobar
def os_urandom_mock():
return 'mocked'
def foobar_mock():
return 'mocked'
class TestProject(unittest.TestCase):
@patch(__name__ + '.foobar', side_effect=foobar_mock)
def test_foobar_mocked(self, foobar_mocked):
self.assertEqual(foobar(), 'mocked')
@patch(__name__ + '.foobar')
def test_foobar_mocked_another(self, foobar_mocked):
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
def test_foobar_mocked_last_try(self):
with patch(__name__ + '.foobar') as foobar_mocked:
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
unittest.main()
请注意,在大多数情况下,您将修补被测模块正在导入的内容,而不是直接在测试中调用修补后的函数。在这个的情况下,事情往往更清晰:
<强> asdf.py 强>:
def baz():
return 'baz'
<强> project.py:强>
from asdf import baz
def foobar():
return baz()
<强> tests.py:强>
import unittest
from unittest.mock import patch
import os
from project import foobar
def baz_mock():
return 'mocked'
class TestProject(unittest.TestCase):
@patch('project.baz', side_effect=baz_mock)
def test_foobar_mocked(self, foobar_mocked):
self.assertEqual(foobar(), 'mocked')
@patch('project.baz')
def test_foobar_mocked_another(self, baz_mocked):
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
def test_foobar_mocked_last_try(self):
with patch('project.baz') as baz_mocked:
foobar_mocked.return_value = 'mocked'
self.assertEqual(foobar(), 'mocked')
unittest.main()
答案 1 :(得分:0)
事实上,我真正想做的是模仿post_save
django
信号,所以this do the trick