2015-11-07 126 views
2

我正在使用python的unittest.mock在Django应用程序中执行一些测试。我想检查一个类是否被调用,并且它的实例上的方法也被调用。模拟python单元测试中的类和类方法

例如,给定这个简化的示例代码:

# In project/app.py 
def do_something(): 
    obj = MyClass(name='bob') 
    return obj.my_method(num=10) 

而这个测试来检查发生的事情:

# In tests/test_stuff.py 
@patch('project.app.MyClass') 
def test_it(self, my_class): 
    do_something() 
    my_class.assert_called_once_with(name='bob') 
    my_class.my_method.assert_called_once_with(num=10) 

试验成功说my_class被调用,但是他说,my_class.my_method不调用。我知道我错过了一些东西 - 嘲笑模拟课堂上的一种方法? - 但我不确定什么或如何使它工作。

回答

2

你的第二个模拟断言需要测试你是在实例调用my_method,而不是类本身。

调用模拟对象这样,

my_class().my_method.assert_called_once_with(num=10) 
     ^^ 
+0

Doh!我花了很长时间看着我认为我做错了嘲笑,我错过了那个愚蠢的错误!谢谢Jared。 –

1

如果my_method是一个类的方法这一行

my_class.my_method.assert_called_once_with(num=10) 

会工作。

是这样吗?

否则,如果my_method仅仅是一个正常的实例方法,那么你就需要重构功能do_something来获得实例变量obj

例如握住

def do_something(): 
    obj = MyClass(name='bob') 
    return obj, obj.my_method(num=10) 

# In tests/test_stuff.py 
@patch('project.app.MyClass') 
def test_it(self, my_class): 
    obj, _ = do_something() 
    my_class.assert_called_once_with(name='bob') 
    obj.my_method.assert_called_once_with(num=10) 
+0

谢谢安东尼。在某种程度上,这与Jared的回答有何不同? (我不是说它不是,我只是不明白就知道!) –

1

小重构建议为你的单元测试,以帮助其他的实例方法你可能在你的测试遇到。而不是在每种方法中嘲笑你的课程,你可以在setUp方法中设置这一切。这样,当班级嘲笑并从该班级创建模拟对象时,您现在可以根据需要多次使用该对象,测试班级中的所有方法。

为了说明这一点,我将下面的例子放在一起。评论在线:

class MyTest(unittest.TestCase): 

    def setUp(self): 
     # patch the class 
     self.patcher = patch('your_module.MyClass') 
     self.my_class = self.patcher.start() 

     # create your mock object 
     self.mock_stuff_obj = Mock() 
     # When your real class is called, return value will be the mock_obj 
     self.my_class.return_value = self.mock_stuff_obj 

    def test_it(self): 
     do_something() 

     # assert your stuff here 
     self.my_class.assert_called_once_with(name='bob') 
     self.mock_stuff_obj.my_method.assert_called_once_with(num=10) 

    # stop the patcher in the tearDown 
    def tearDown(self): 
     self.patcher.stop() 

提供关于这是如何放在一起时,setUp方法,我们将提供功能能够跨作为文档here解释多种方法应用补丁里面的一些见解。

的修补是在这两条线进行:

# patch the class 
    self.patcher = patch('your_module.MyClass') 
    self.my_class = self.patcher.start() 

最后,在这里创建的模拟对象:

# create your mock object 
    self.mock_stuff_obj = Mock() 
    self.my_class.return_value = self.mock_stuff_obj 

现在,所有的测试方法可以简单地在所有使用self.my_classself.mock_stuff_obj你的电话。

+0

谢谢idjaw。我后来开始做一些这样的事情,但这仍然非常有用,谢谢! –