4

Python的unittest.mock模块中提供了两个主要的mock类,分别是MockMagicMock.

先看一下官方文档的定义:

MagicMock is a subclass of Mock with all the magic methods pre-created and ready to use.

其实已经很清楚了,MagicMock是Mock的子类,并且预先创建了全部magic method的mock。
也就是说,如果不需要mock magic method,两者使用起来并没有什么分别。

来看个例子,先定义个类,里面只有一个成员方法,返回10倍的数值:

class Person:
    def get_10_times_value(self, value)
        return 10 * value

使用Mock类来mock掉这个成员方法:

def test_should_mock_get_10_times_value_with_Mock(self):
    p = Person()
    p.get_10_times_value = Mock(return_value=100)
    
    self.assertEqual(p.get_10_times_value(), 100)

使用MagicMock类来mock:

def test_should_mock_get_10_times_value_with_MagicMock(self):
    p = Person()
    p.get_10_times_value = MagicMock(return_value=100)
    
    self.assertEqual(p.get_10_times_value(), 100)

两者没有任何区别,都成功了mock了成员方法。

再看下两者的区别:

def test_should_raise_exception(self):
    m = Mock()
    list(m)

TypeError: 'Mock' object is not iterable

因为使用Mock类时,默认不会创建__iter__这个magic method的mock,所以报错。

如果想mock __iter__这个方法,得自己去做,如下:

def test_should_mock_magic_method_with_Mock(self):
    m = Mock()
    m.__iter__ = Mock(return_value=iter([]))
    
    self.assertEqual(list(m), [])

而使用MagicMock类时默认就会mock掉所有的magic method,所以不需要自己mock,__iter__默认是空数组:

def test_should_mock_magic_method_with_MagicMock(self):
    m = MagicMock()
    
    self.assertEqual(list(m), [])

因为已经默认创建了magic method的mock,所以可以直接使用return_value属性来改变值:

def test_should_mock_magic_method_with_MagicMock(self):
    m = MagicMock()
    m.__iter__.return_value = [1, 2, 3]
    
    self.assertEqual(list(m), [1, 2, 3])

其他magic method类似。


带着大馒头写代码
50 声望1 粉丝