mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。
参考:
-
Mock Class:
class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)¶
MagicMock是Mock的子类。
-
当mock被调用之后,它的called属性将会被设置为
True
,我们也可以调用其assert_called_with()
或者assert_called_once_with()
来检查是否正确的调用。from mock import MagicMock class ProductionClass(object): def closer(self, something): something.close() real = ProductionClass() mock = MagicMock() real.closer(mock) print mock.close.called mock.close.assert_called_once_with() 结果: True
在大多数情况下,Mock和MagicMock是可以交换使用的,MagicMock是Mock的子类。
-
return_value的使用
class ProductionClass(object): def __init__(self): pass def method(self): return "the result"
from mock import MagicMock from mock import patch from learnmock03 import ProductionClass def some_function(): instance = ProductionClass() return instance.method() with patch('learnmock03.ProductionClass') as mock: # 使用mock调用 instance = mock.return_value instance.method.return_value = 'the result' # 创建对象调用 result = some_function() assert result == 'the result'
-
在创建Mock的时候可以设置
name
参数。 -
设置返回值和属性
需要导入
from mock import Mock
-
设置返回值
>>> mock = Mock() >>> mock.return_value = 3 >>> mock() 返回: 3
>>> mock = Mock() >>> mock.method.return_value = 3 >>> mock.method() 返回: 3
>>> mock = Mock(return_value=3) >>> mock() 返回: 3
-
设置属性
>>> mock = Mock() >>> mock.x = 3 >>> mock.x 返回: 3
-
-
Side effect
-
将side_effect的值设置为
None
来清除side_effect -
side_effect是一个方法,当mock被调用的时候,side_effect也会被调用。side_effect可以被赋值为一个函数或者是异常,在调用mock时,side_effect也会被执行:
from mock import MagicMock class Class: def method(self): pass def method(): print "print side_effect" mock = MagicMock(side_effect = method) mock() mock.assert_called_once__with()
将会打印:print side_effect
若将side_effect设置为某个异常,例如
side_effect=Exception("Boom!")
,则在调用mock时将会抛出异常。
-
-
Decorators
-
patch
使用一个简单的string,格式为:
package.module.Class.attribute
>>> @patch('__main__.SomeClass') ... def function(normal_argument, mock_class): ... print(mock_class is SomeClass)
@patch所产生的对象将会传给所修饰的方法,并作为方法的最后一个参数,在上面的代码中则是mock_class;
注意如果patch的类在当前文件中定义,@patch的字符串参数要使用
__main__
修饰;看下面的情况:
from mock import patch class Class01: def method(self): pass class Class02: def method(self): pass @patch("__main__.Class01") @patch("__main__.Class02") def test(mockClass02, mockClass01): assert mockClass02.return_value is Class02() assert mockClass01.return_value is Class01() test()
当有多个@patch修饰同一个方法时,遵循bottom---->up的顺序,为方法传参。
-
patch.object
使用
一个对象+该对象上的一个属性的名字[+]属性的值
- 类属性:
from mock import patch class SomeClass: attribute = "originalvalue" @patch.object(SomeClass, 'attribute', 'sentinel.attribute') def test(): print SomeClass.attribute assert SomeClass.attribute == 'sentinel.attribute' test() 结果: sentinel.attribute
- 实例属性:
from mock import patch class SomeClass: def __init__(self, attr): self.attr = attr original = SomeClass("attr_value") print original @patch.object(original, 'attr', 'sentinel.attribute') def test(): print original.attr assert original.attr == 'sentinel.attribute_2' test()
-
patch.dict
-
-
当使用patch创建mock时,将会返回该mock的引用,使用as接收
with patch.object(ProductionClass, 'method') as mock_method: ...
-
获得instance的两种方式
>>> class Class: ... def method(self): ... pass ... >>> with patch('__main__.Class') as MockClass: ... instance = MockClass.return_value ... instance.method.return_value = 'foo' ... assert Class() is instance ... assert Class().method() == 'foo'
>>> Original = Class >>> patcher = patch('__main__.Class', spec=True) >>> MockClass = patcher.start() >>> instance = MockClass() >>> assert isinstance(instance, Original) >>> patcher.stop()
mock() == mock.return_value