我试图弄到一套嘲弄对象的窍门,似乎被一些非常基本的东西弄糊涂了。我试图模拟对象MyClass,然后对它的一个方法进行单元测试。这是我的代码:
import mock
import unittest
class MyClass(object):
def __init__(self, a):
self.a = a
def add_two(self):
return self.a + 2
class TestMyClass(unittest.TestCase):
@mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
m_my_class = mock.Mock()
m_my_class.a = 10
result = m_my_class.add_two() # I would expect the result to be 12
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
if __name__ == '__main__':
unittest.main()
在m_my_class.a = 10
中,我将a
的值设置为to,然后在m_my_class.add_two()
中添加一个2,难道我不应该得到12吗?然而,result
是:
我错过了什么?在
由于我通过decorator将类的位置传递给测试方法@mock.patch('__main__.MyClass')
,mocked不应该拥有所有的方法吗?因为如果不是,那么在decorator中包含什么类又有什么关系呢?在
编辑:
当我运行这个代码时,我仍然得到同样的结果。在
class TestMyClass(unittest.TestCase):
@mock.patch('__main__.MyClass')
def test_add_two(self, dummy_mock):
dummy_mock.a = 10
result = dummy_mock.add_two()
import ipdb;ipdb.set_trace()
self.assert_equal(result, 12)
结果:
ipdb> result
<MagicMock name='MyClass.add_two()' id='38647312'>
修补类几乎肯定不是你想在这里做的。例如,如果您将测试方法更改为:
你会发现这并不是你所期望的:
^{pr2}$你会得到这个:
修补方法中的类意味着在方法中的任何时候,如果某个东西试图实例化类,它将得到一个模拟对象。在您的特定情况下,调用
MyClass(5)
将返回与调用dummy_mock
相同的模拟对象。这允许您设置模拟对象,以便在您测试代码时,模拟对象将按您希望的方式运行。在你真的只会把它用于依赖关系,而不是你正在测试的类。因此,例如,如果您的类从SQL中检索到数据,那么您应该修补SQL类以使您的类具有mock而不是普通的SQL连接。这使您能够独立地测试一个类,而不必担心外部(如SQL)会妨碍您。在
不过,在您的示例中,您似乎在尝试单独测试一个方法。一种方法是从方法中提取函数并使用它。代码:
通常,您不必为
self
参数传入参数,但正如这里我们已经拉出了您确实需要传入self
参数的函数。如果需要,可以将函数转换为绑定到模拟对象的方法,如下所示:如果正在测试的函数调用任何其他方法,则需要对每个方法执行此操作或模拟它。在
我建议不要过多地使用这种策略,部分原因是需要处理被测试方法调用的方法。当然,能够模仿它所依赖的方法可能正是你想要做的。无论如何,它要求单元测试对方法如何工作有相当深入的理解,而不仅仅是它应该产生什么。这使得测试变得非常脆弱,使得您很可能比正在测试的方法更经常地看到测试中断。在
你为什么嘲笑你的小苏?这通常是你应该避免做的事情,因为它会带来风险,你不会去测试你认为你正在测试的东西。在
单元测试的目的是在完全隔离的情况下验证单元的行为。一个单元通常与其他单元协作以提供一些有用的功能。Test doubles(mock、fakes等)是用来实现这种隔离的工具。在单元测试中,SUT的协作者被替换为测试双精度,以便minimize the number of moving parts。在
您的SUT
MyClass
似乎没有任何合作者。因此,不需要双重测试来单独测试这个单元(它已经是独立的)。这样可以大大简化单元测试:编辑:下面的代码演示如何使用模拟对象。(免责声明:我通常不使用Python,所以我的代码可能是not very idiomatic。不过,希望核心点还是有道理的。)
在本例中,
^{pr2}$MyClass
添加由协作者提供的值,而不是核心值(2)。在上面的例子使用了一个模拟对象,而不是修补一个类。这里有一个很好的解释:
Mocking a class: Mock() or patch()?
相关问题 更多 >
编程相关推荐