可以通过以下方式模拟打印:
import unittest
import builtin
class TestSomething(unittest.TestCase):
@mock.patch('builtins.print')
def test_method(self, print_):
some_other_module.print_something()
但是这意味着在python调试控制台(pydev调试器)和单元测试方法本身print
中不能使用。这很不方便。
有没有办法只在print
而不是在测试模块中模仿some_other_module
方法?
回避这一点的一种方法是将测试模块中print的使用与只调用print
的其他函数交换,如果事实证明没有更好的解决方案,我可以这样做。
答案 0 :(得分:6)
是的,你可以! ...但仅仅因为你使用的是Python 3.在Python 3中print
是一个函数,您可以在不更改名称的情况下重写它。为了理解最终解决方案,我将逐步描述它以获得最终灵活且非侵入性的解决方案。
诀窍是在你的模块顶部添加你将测试一行如下:
print = print
现在你可以只修补你的模块的print
。我写了一个测试用例mock_print_module.py
:
print = print
def print_something():
print("print something")
测试模块(我使用autospec=True
只是为了避免像mock_print.asser_called_with
这样的错误):
from unittest import TestCase
from unittest.mock import patch
import mock_print_module
class MyTestCase(TestCase):
@patch("mock_print_module.print",autospec=True)
def test_something(self,mock_print):
mock_print_module.print_something()
mock_print.assert_called_with("print something")
您只需使用patch
"builtins.print"
的属性,就可以side_effect
使用patch
而不会失去打印功能:
@patch("builtins.print",autospec=True,side_effect=print)
def test_somethingelse(self,mock_print):
mock_print_module.print_something()
mock_print.assert_called_with("print something")
现在,您可以在不丢失日志记录和pydev调试器的情况下跟踪您的打印调用。这种方法的缺点是你必须对抗很多噪音,以检查你感兴趣的打印电话。此外,您无法选择要修补的模块和不适用的模块。
您不能同时使用这两种方式,因为如果您在模块中使用print=print
,则会在加载模块时将builtins.print
保存在print
变量中。现在,当您修补builtins.print
时,模块仍然使用原始保存的模块。
如果你有机会同时使用它们,你必须包装原始印刷品而不是记录它。实现它的方法是使用以下代替print=print
:
import builtins
print = lambda *args,**kwargs:builtins.print(*args,**kwargs)
我们是否真的需要修改原始模块才有机会修补其中的所有打印调用?不,我们无需更改模块即可完成测试。我们唯一需要的是在模块中注入一个本地print
函数来覆盖builtins
的一个:我们可以在测试模块而不是要测试的模块中完成。我的例子将成为:
from unittest import TestCase
from unittest.mock import patch
import mock_print_module
import builtins
mock_print_module.print = lambda *args,**kwargs:builtins.print(*args,**kwargs)
class MyTestCase(TestCase):
@patch("mock_print_module.print",autospec=True)
def test_something(self,mock_print):
mock_print_module.print_something()
mock_print.assert_called_with("print something")
@patch("builtins.print",autospec=True,side_effect=print)
def test_somethingelse(self,mock_print):
mock_print_module.print_something()
mock_print.assert_called_with("print something")
和mock_print_module.py
可以是干净的原始版本,只有:
def print_something():
print("print something")
答案 1 :(得分:6)
@ michele的“最终解决方案”有一个更清晰的替代方案,适用于我的情况:
from unittest import TestCase
from unittest.mock import patch
import module_under_test
class MyTestCase(TestCase):
@patch('module_under_test.print', create=True)
def test_something(self, print_):
module_under_test.print_something()
print_.assert_called_with("print something")