Weh*_*olt 17 python unit-testing mocking
我想在python中伪造一个包.我想定义一些代码可以做的事情
from somefakepackage.morefakestuff import somethingfake
Run Code Online (Sandbox Code Playgroud)
并且somefakepackage在代码中定义,因此它下面的所有内容都是如此.那可能吗?这样做的原因是欺骗我的单元测试我得到了一个包(或者我在标题中说的一个模块)在python路径中实际上只是为这个单元测试模拟的东西.
谢谢!
kin*_*all 30
当然.定义一个类,将所需内容放入其中,将类分配给sys.modules["classname"].
class fakemodule(object):
@staticmethod
def method(a, b):
return a+b
import sys
sys.modules["package.module"] = fakemodule
Run Code Online (Sandbox Code Playgroud)
您还可以使用单独的模块(称之为fakemodule.py):
import fakemodule, sys
sys.modules["package.module"] = fakemodule
Run Code Online (Sandbox Code Playgroud)
ide*_*n42 13
是的,你可以制作假模块:
from types import ModuleType
m = ModuleType("fake_module")
import sys
sys.modules[m.__name__] = m
# some scripts may expect a file
# even though this file doesn't exist,
# it may be used by Python for in error messages or introspection.
m.__file__ = m.__name__ + ".py"
# Add a function
def my_function():
return 10
m.my_function = my_function
Run Code Online (Sandbox Code Playgroud)
注意,在这个例子中它使用了一个实际的模块,ModuleType因为一些Python代码可能需要模块,而不是虚拟类.
这可以做成一个效用函数:
def new_module(name, doc=None):
import sys
from types import ModuleType
m = ModuleType(name, doc)
m.__file__ = name + '.py'
sys.modules[name] = m
return m
print(new_module("fake_module", doc="doc string"))
Run Code Online (Sandbox Code Playgroud)
现在其他脚本可以运行:
import fake_module
Run Code Online (Sandbox Code Playgroud)
小智 7
我从其他答案中汲取了一些想法,并将它们转换为 Python 装饰器@modulize,将函数转换为模块。然后可以像往常一样导入该模块。这是一个例子。
@modulize('my_module')
def my_dummy_function(__name__): # the function takes one parameter __name__
# put module code here
def my_function(s):
print(s, 'bar')
# the function must return locals()
return locals()
# import the module as usual
from my_module import my_function
my_function('foo') # foo bar
Run Code Online (Sandbox Code Playgroud)
装饰器的代码如下
import sys
from types import ModuleType
class MockModule(ModuleType):
def __init__(self, module_name, module_doc=None):
ModuleType.__init__(self, module_name, module_doc)
if '.' in module_name:
package, module = module_name.rsplit('.', 1)
get_mock_module(package).__path__ = []
setattr(get_mock_module(package), module, self)
def _initialize_(self, module_code):
self.__dict__.update(module_code(self.__name__))
self.__doc__ = module_code.__doc__
def get_mock_module(module_name):
if module_name not in sys.modules:
sys.modules[module_name] = MockModule(module_name)
return sys.modules[module_name]
def modulize(module_name, dependencies=[]):
for d in dependencies: get_mock_module(d)
return get_mock_module(module_name)._initialize_
Run Code Online (Sandbox Code Playgroud)
该项目可以在 GitHub 上找到。特别是,我为编程比赛创建了这个,它只允许参赛者提交一个.py文件。这允许开发一个包含多个 .py 文件的项目,然后最后将它们组合成一个.py文件。
补丁sys.modules使用unittest.mock:
mock.patch.dict(\n sys.modules,\n {\'somefakepackage\': mock.Mock()},\n)\nRun Code Online (Sandbox Code Playgroud)\n其他答案正确地建议修复sys.modules,但正确的方法是使用临时修补它mock.patch。仅当使用模仿所需行为的假对象运行测试时,它才会替换模块。并在测试完成后将其恢复,以免影响其他测试用例。
TL;DR 部分中的代码只会使您丢失的包不会引发ImportError。要提供假包的内容并模仿所需的行为,请mock.Mock(\xe2\x80\xa6)使用适当的参数启动(例如通过 Mock\'s 添加属性**kwargs)。
下面的代码临时修补sys.modules,以便它包含somefakepackage并使其可以从不带ImportError.
import sys\nimport unittest\nfrom unittest import mock\n\nclass SomeTestCase(unittest.TestCase):\n def test_smth(self):\n # implement your testing logic, for example:\n self.assertEqual(\n 123,\n somefakepackage_dependent.some_func(),\n )\n\n @classmethod\n def setUpClass(cls): # called once before all the tests\n # define what to patch sys.modules with\n cls._modules_patcher = mock.patch.dict(\n sys.modules,\n {\'somefakepackage\': mock.Mock()},\n )\n # actually patch it\n cls._modules_patcher.start()\n # make the package globally visible and import it,\n # just like if you have imported it in a usual way\n # placing import statement at the top of the file,\n # but relying on a patched dependency\n global somefakepackage_dependent\n import somefakepackage_dependent\n\n @classmethod # called once after all tests\n def tearDownClass(cls):\n # restore initial sys.modules state back\n cls._modules_patcher.stop()\n\nRun Code Online (Sandbox Code Playgroud)\n要了解有关setUpClass/tearDownClass方法的更多信息,请参阅unittestdocs。
unittest\的内置mock分包实际上是一个非常强大的工具。深入研究其文档以获得更好的理解。
你可以用一个行为像这样的类来伪造它somethingfake:
try:
from somefakepackage.morefakestuff import somethingfake
except ImportError:
class somethingfake(object):
# define what you'd expect of somethingfake, e.g.:
@staticmethod
def somefunc():
...
somefield = ...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7694 次 |
| 最近记录: |