我正在为办公室里的其他人写的代码编写一些单元测试。 Python不是我最强的语言。虽然我已经成功完成了基本的单元测试,但是在python中进行模拟会让我陷入困境。
我需要做的是覆盖对ConfigObj的调用,并将我自己的mock config / fixture注入任何ConfigObj调用。
settings.py
from configobj import ConfigObj
config = ConfigObj('/etc/myapp/config')
utils.py
from settings import config
"""lots of stuff methods using various config values."""
我想做的是,在我的utils.py单元测试中,为自己调用ConfigObj或settings.py本身注入自己。
许多模拟库都希望我模拟自己的类,但就这个应用而言,它没有任何明确的类。
是否可以完成或者python命名空间限制是否过于严格以至于我无法干预我正在导入的模块本身导入的内容?
旁注:运行2.7所以我不能做任何我从2.5中读过的技巧。
答案 0 :(得分:2)
如果测试位于settings.py
和utils.py
的单独文件中,您可以创建文件mock.py
import configobj
class MockConfigObj(object):
#mock whatever you wan
configobj.ConfigObj = MockConfigObj
然后import mock
在导入(从)任何自己导入settings
的模块之前。这将确保使用settings.config
创建MockConfigObj
。如果您想要统一的全局模拟,请在导入configobj
的任何文件之前导入它。
这是有效的,因为python会将configobj
存储在sys.modules
中并在实际读取后续导入文件之前检查它。在mock.py
中,标识符ConfigObj
只是对sys.modules
中条目的引用,因此您所做的任何更改都将全局可见。
虽然这让我觉得有点哈哈,但这是我能想到的最好的。
答案 1 :(得分:1)
Python命名空间在同一范围内根本不严格。只需覆盖包含您的对象(或类本身并提供它)的变量名称,在您期望的原始范围内,这就足够了。
现在,你所取代它的行为是否相同取决于你......
答案 2 :(得分:0)
难道你不能用另一个覆盖原来的功能吗?
Python中没有常量,您可以更改所有内容,甚至可以True = False
。
答案 3 :(得分:0)
我之前遇到过类似的情况。以下是我如何解决您的问题。
考虑来自utils.py
的函数的测试用例。
import utils, unittest
class FooFunctionTests(unittest.TestCase):
def setUp(self):
utils._old_config = utils.config
utils.config = MockClass()
def tearDown(self):
utils.config = utils._old_config
del utils._old_config
def test_foo_function_returns_correct_value(self):
self.assertEqual("success!", utils.foo())
答案 4 :(得分:0)
以下页面是关于模拟和导入的好页面
http://www.relaxdiego.com/2014/04/mocking-objects-in-python.html
假设您有一个名为my_package1.py的文件,其中包含以下代码:
class A(object):
def init(self):
然后使用代码
将其导入my_package2.py中
from my_package1 import A
class A(object):
def init(self):
my_package2.py的第一行在名为A的my_package2名称空间下创建一个变量。现在你有两个变量my_package1.A和my_package2.A,它们都指向内存中的同一个类。如果你希望my_package2.py中的代码使用模拟的类A,那么你需要模拟my_package2.A而不是my_package1.A