Listing Nine shows a slightly different use. In this one, I call the mocked method callFoo() , first without input, and then with the string "zort" . The first assert passes (line 20), because callFoo() is not supposed to get any input. And the second assert fails (line 24) for obvious reasons. Listing Nine from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.callFoo.assert_called_with()
# assertion passes
mockFoo.callFoo("zort")
mockFoo.callFoo.assert_called_with()
# AssertionError: Expected call: callFoo()
# Actual call: callFoo('zort') The next assert is assert_called_once_with() . Like assert_called_with() , this assert checks if the test subject called a mocked method correctly. Butassert_called_once_with() will fire when the same method call happens more than once, whereas assert_called_with() will ignore multiple calls. Listing Ten shows how one might use the assert. Here, I make two calls to the mocked method callFoo() . On the first call (lines 19-20), the assert passes. But on the second call (lines 23-24), the assert fires, sending its error message to stdout . Listing Ten from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.callFoo.assert_called_once_with()
# assertion passes
mockFoo.callFoo()
mockFoo.callFoo.assert_called_once_with()
# AssertionError: Expected to be called once. Called 2 times. The assert assert_any_call() checks if the test subject called a mocked method at any point of the test routine. This is regardless of how many other calls were made between the mocked method and the assert. Compare this with the previous two asserts, both of which check only the most recent call. Listing Eleven shows the assert_any_call() assert at work: still the same mock object, with class Foo as its spec. The first call is to the methodcallFoo() (line 18), the next two to doFoo() (lines 19-20). Notice thatdoFoo() gets two different inputs. |
译者信息 Listing Nine显示了稍微不同的用法。在这个例子中,我调用了mock方法callFoo(),首先没有任何输入,然后输入了字符串“zort”。第一个断言通过了(第20行),因为callFoo()不支持获得任何输入。而第二个断言失败了(第24行)因为显而易见的原因。 Listing Nine from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.callFoo.assert_called_with()
# assertion passes
mockFoo.callFoo("zort")
mockFoo.callFoo.assert_called_with()
# AssertionError: Expected call: callFoo()
# Actual call: callFoo('zort') 先一个断言是assert_called_once_with()。像assert_called_with()一样,这个断言检查测试对象是否正确的调用了mock方法。但是当同样的方法调用超过一次时, assert_called_once_with()将引发错误,然而assert_called_with()会忽略多次调用。Listing Ten显示了怎样使用这个断言。那儿,我调用了mock方法callFoo()两次。第一次调用时(行19~20),断言通过。但是在第二次调用的时(行23~24),断言失败,发送了错误消息到stdout。 Listing Ten from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.callFoo.assert_called_once_with()
# assertion passes
mockFoo.callFoo()
mockFoo.callFoo.assert_called_once_with()
# AssertionError: Expected to be called once. Called 2 times. 断言assert_any_call(),检查测试对象在测试例程中是否调用了测试方法。它不管mock方法和断言之间有多少其他的调用。和前面两个断言相比较,前两个断言仅检查最近一次的调用。 Listing Eleven显示了assert_any_call()断言如何工作:仍然是同样的mock对象,spec参数是Foo类。第一个调用方法callFoo()(第18行),接下来调用两次doFoo()(行19~20)。注意doFoo()获得了两个不同的输入。 |
Listing Eleven <from mock import Mock
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
mockFoo.callFoo.assert_any_call()
# assert passes
mockFoo.callFoo()
mockFoo.doFoo("troz")
mockFoo.doFoo.assert_any_call("zort")
# assert passes
mockFoo.doFoo.assert_any_call("egad")
# raises: AssertionError: doFoo('egad') call not found The first assert_any_call() (line 22) passes even though two doFoo() calls separate the assert and callFoo() . The second assert (line 28) also passes even though a callFoo() separates it from the doFoo() in question (line 20). On the other hand, the third assert (line 31) fires, because none of thedoFoo() calls used the string "egad" for input. Finally, there is assert_has_calls() . This one looks at a sequence of method calls, checks if they are in the right order and with the right arguments. It takes two arguments: a list of expected method calls and an optional argument any_order . It fires when the test subject calls the wrong method, calls one method out of order, or gives a method the wrong input. |
译者信息 Listing Eleven <from mock import Mock
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
mockFoo.callFoo.assert_any_call()
# assert passes
mockFoo.callFoo()
mockFoo.doFoo("troz")
mockFoo.doFoo.assert_any_call("zort")
# assert passes
mockFoo.doFoo.assert_any_call("egad")
# raises: AssertionError: doFoo('egad') call not found 第一个assert_any_call()(第22行)通过,虽然两次doFoo()调用隔开了断言和callFoo()。第二个断言(第28行)也通过了,虽然一个callFoo()隔开了我们提到的doFoo()(第20行)。另一方面,第三个断言(第31行)失败了,因为没有任何doFoo()的调用使用了"egad"的输入。 最后,还有assert_has_calls()。它查看方法调用的顺序,检查他们是否按正确的次序调用并带有正确的参数。它带有两个参数:期望调用方法的列表和一个可选悬殊any_order。当测试对象调用了错误的方法,调用了不在次序中的方法,或者方法获得了一个错误的输入,将生产断言错误。 |
Listing Twelve demonstrates the assert_has_calls() assert. In lines 18-20, I make three method calls, providing input to two. Then, I prepare a list of expected calls (fooCalls ) and pass this list to assert_has_calls() (lines 22-23). Since the list matches the method calls, the assert passes. Listing Twelve from mock import Mock, call
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
fooCalls = [call.callFoo(), call.doFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls)
# assert passes
fooCalls = [call.callFoo(), call.doFoo("zort"), call.doFoo("narf")]
mockFoo.assert_has_calls(fooCalls)
# AssertionError: Calls not found.
# Expected: [call.callFoo(), call.doFoo('zort'), call.doFoo('narf')]
# Actual: [call.callFoo(), call.doFoo('narf'), call.doFoo('zort')]
fooCalls = [call.callFoo(), call.doFoo("zort"), call.doFoo("narf")]
mockFoo.assert_has_calls(fooCalls, any_order = True)
# assert passes In line 26, I swapped the two doFoo() calls around. The first doFoo() gets "zort" for input, the second gets "narf" . If I pass this fooCalls toassert_has_calls() (line 27), the assert fires. But if I pass a True to theany_order argument, the assert passes. This is because the assert now ignores the order in which the method calls were made. |
译者信息 Listing Twelve演示了assert_has_calls()断言。在18~20行,我调用了三个方法,提供了两个输入。然后,我准备了一个期望调用的列表(fooCalls)并把这个列表传入assert_has_calls()(22~23行)。由于列表匹配了方法的调用,断言通过。 Listing Twelve from mock import Mock, call
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
fooCalls = [call.callFoo(), call.doFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls)
# assert passes
fooCalls = [call.callFoo(), call.doFoo("zort"), call.doFoo("narf")]
mockFoo.assert_has_calls(fooCalls)
# AssertionError: Calls not found.
# Expected: [call.callFoo(), call.doFoo('zort'), call.doFoo('narf')]
# Actual: [call.callFoo(), call.doFoo('narf'), call.doFoo('zort')]
fooCalls = [call.callFoo(), call.doFoo("zort"), call.doFoo("narf")]
mockFoo.assert_has_calls(fooCalls, any_order = True)
# assert passes 在第26行,我交换了两个doFoo()调用的顺序。第一个doFoo()获得"zort"的输入,第二个获得了"narf"。如果我传入这个fooCalls到assert_has_calls()(第27行)中,断言失败。但是如果我给参数any_order传入参数True,断言通过。这是因为断言将忽略方法调用的顺序。 |
Listing Thirteen demonstrates another use. To the list fooCalls , I added a nonexistent method dooFoo() (line 22). Then I passed fooCalls toassert_has_calls( ) (line 24). The assert fires, informing me that the expected call sequence did not match what actually happened. If I pass aTrue to the any_order argument (line 30), the assert names dooFoo() as the offending method call. Listing Thirteen from mock import Mock, call
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls)
# AssertionError: Calls not found.
# Expected: [call.callFoo(), call.dooFoo('narf'), call.doFoo('zort')]
# Actual: [call.callFoo(), call.doFoo('narf'), call.doFoo('zort')]
fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls, any_order = True)
# AssertionError: (call.dooFoo('narf'),) not all found in call list In both examples for assert_has_calls() , note the call keyword that appears before each method name. This keyword is for a helper object, one that marks out a method attribute in the mock object. To use the call keyword, make sure to import the helper from the mock module as follows: from mock import Mock, call |
译者信息 Listing Thirteen演示了其他的用法。在fooCalls列表中,我添加了不存在的方法dooFoo()(第22行)。然后我传入fooCalls到assert_has_calls()中(第24行)。断言失败,通知我期望调用的顺序和真实发生的顺序不匹配。如果我给any_order赋值为True(第30行),断言名称dooFoo()作为违规的方法调用。 Listing Thirteen from mock import Mock, call
# The mock specification
class Foo(object):
_fooValue = 123
def callFoo(self):
pass
def doFoo(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
mockFoo.callFoo()
mockFoo.doFoo("narf")
mockFoo.doFoo("zort")
fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls)
# AssertionError: Calls not found.
# Expected: [call.callFoo(), call.dooFoo('narf'), call.doFoo('zort')]
# Actual: [call.callFoo(), call.doFoo('narf'), call.doFoo('zort')]
fooCalls = [call.callFoo(), call.dooFoo("narf"), call.doFoo("zort")]
mockFoo.assert_has_calls(fooCalls, any_order = True)
# AssertionError: (call.dooFoo('narf'),) not all found in call list 在assert_has_calls()的两个例子中,注意到关键字call是出现在每个方法的前面。这个关键字是一个helper对象,标记出mock对象的方法属性。为了使用call关键字,请确保使用如下的方法从mocke模块导入helper: from mock import Mock, call |
Managing a Mock A third set of methods from the Mock class allow you to control and manage your mock object. You can change how the mock behaves, alter some of its attributes, or restore the mock to its pre-test state. You can even change the response values for each mocked method or for the mock itself. The method attach_mock() lets you add a second mock object to your mock. This method takes two arguments: the second mock object (aMock ) and an attribute name (aName ). Listing Fourteen demonstrates how this is done. Here, I create two mock objects, mockFoo and mockBar , each one with a different spec (lines 25, 30). To mockFoo , I add mockBar using attach_mock() and the name "fooBar " (line 35). Once that is done, I can access the second mock and its attributes via the property fooBar (lines 46-53). And I can still access the attributes for the first mock, mockFoo (lines 40-43). Listing Fourteen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
class Bar(object):
# instance properties
_barValue = 456
def callBar(self):
pass
def doBar(self, argValue):
pass
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
# create the second mock object
mockBar = Mock(spec = Bar)
print mockBar
# returns: <Mock spec='Bar' id='2784400'>
# attach the second mock to the first
mockFoo.attach_mock(mockBar, 'fooBar')
# access the first mock's attributes
print mockFoo
# returns: <Mock spec='Foo' id='495312'>
print mockFoo._fooValue
# returns: <Mock name='mock._fooValue' id='428976'>
print mockFoo.callFoo()
# returns: <Mock name='mock.callFoo()' id='448144'>
# access the second mock and its attributes
print mockFoo.fooBar
# returns: <Mock name='mock.fooBar' spec='Bar' id='2788592'>
print mockFoo.fooBar._barValue
# returns: <Mock name='mock.fooBar._barValue' id='2788016'>
print mockFoo.fooBar.callBar()
# returns: <Mock name='mock.fooBar.callBar()' id='2819344'>
print mockFoo.fooBar.doBar("narf")
# returns: <Mock name='mock.fooBar.doBar()' id='4544528'> The method configure_mock() lets you make wholesale changes to the mock object. Its sole argument is a sequence of key/value pairs, each key being the attribute you want changed. If the mock does not have the specified attribute, configure_mock() will add the attribute to the mock. |
译者信息 管理Mock Mock类的第三套方法允许你控制和管理mock对象。你可以更改mock的行为,改变它的属性或者将mock恢复到测试前的状态。你甚至可以更改每个mock方法或者mock本身的响应值。attach_mock()方法让你在mock中添加第二个mock对象。这个方法带有两个参数:第二个mock对象(aMock)和一个属性名称(aName)。 Listing Fourteen 样式了attach_mock()方法的使用。那儿,我创建了两个mock对象mockFoo和mockBar,他们有不同spec参数(第25行和第30行)。我用attach_mock()方法将mockBar添加到mockFoo中,命名为fooBar(第35行)。一旦添加成功,我就能通过property fooBar访问第二mock对象和它的属性(46~53行)。并且我仍然可以访问第一个mock对象mockFoo的属性。 Listing Fourteen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
class Bar(object):
# instance properties
_barValue = 456
def callBar(self):
pass
def doBar(self, argValue):
pass
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
# create the second mock object
mockBar = Mock(spec = Bar)
print mockBar
# returns: <Mock spec='Bar' id='2784400'>
# attach the second mock to the first
mockFoo.attach_mock(mockBar, 'fooBar')
# access the first mock's attributes
print mockFoo
# returns: <Mock spec='Foo' id='495312'>
print mockFoo._fooValue
# returns: <Mock name='mock._fooValue' id='428976'>
print mockFoo.callFoo()
# returns: <Mock name='mock.callFoo()' id='448144'>
# access the second mock and its attributes
print mockFoo.fooBar
# returns: <Mock name='mock.fooBar' spec='Bar' id='2788592'>
print mockFoo.fooBar._barValue
# returns: <Mock name='mock.fooBar._barValue' id='2788016'>
print mockFoo.fooBar.callBar()
# returns: <Mock name='mock.fooBar.callBar()' id='2819344'>
print mockFoo.fooBar.doBar("narf")
# returns: <Mock name='mock.fooBar.doBar()' id='4544528'> configure_mock()方法让你批量的更改mock对象。它唯一的参数是一个键值对序列,每个键就是你想要修改的属性。如果你的对象没有指定的属性,configure_mock()将在mock中添加属性。 |
Listing Fifteen shows the configure_mock() method in action. Once again, I have a mock object (mockFoo ) with class Foo for a spec and 555 for areturn_value (line 13). Then with configure_mock() , I changed thereturn_value property to 999 (line 17). When I call mockFoo directly, I get 999 for a result, instead of the original 555 . Listing Fifteen from mock import Mock
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
mockFoo = Mock(spec = Foo, return_value = 555)
print mockFoo()
# returns: 555
mockFoo.configure_mock(return_value = 999)
print mockFoo()
# returns: 999
fooSpec = {'callFoo.return_value':"narf", 'doFoo.return_value':"zort", 'doFoo.side_effect':StandardError}
mockFoo.configure_mock(**fooSpec)
print mockFoo.callFoo()
# returns: narf
print mockFoo.doFoo("narf")
# raises: StandardError
fooSpec = {'doFoo.side_effect':None}
mockFoo.configure_mock(**fooSpec)
print mockFoo.doFoo("narf")
# returns: zort Next, I prepare a dictionary object (fooSpec ) into which I set the return values for two mocked methods and the side effect for doFoo() (line 21). I pass fooSpec into configure_mock() , taking care to prefix fooSpec with '**' (line 22). Invoking callFoo() now returns "narf" as a result; and invokingdoFoo() , regardless of input, raises a StandardError signal (lines 24-27). If I alter fooSpec , setting the side-effect value for doFoo() to None , I get a result of "zort" when invoking doFoo() (lines 29-32). |
译者信息 Listing fifteen显示了configure_mock()方法的运用。再次,我定义了一个spec为类Foo和return_value为555的mock对象mockFoo(第13行)。然后使用configure_mock()方法更改return_value为999(第17行)。当我直接调用mockFoo时,获得的结果为999,替换了原来的555。 Listing Fifteen from mock import Mock
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
mockFoo = Mock(spec = Foo, return_value = 555)
print mockFoo()
# returns: 555
mockFoo.configure_mock(return_value = 999)
print mockFoo()
# returns: 999
fooSpec = {'callFoo.return_value':"narf", 'doFoo.return_value':"zort", 'doFoo.side_effect':StandardError}
mockFoo.configure_mock(**fooSpec)
print mockFoo.callFoo()
# returns: narf
print mockFoo.doFoo("narf")
# raises: StandardError
fooSpec = {'doFoo.side_effect':None}
mockFoo.configure_mock(**fooSpec)
print mockFoo.doFoo("narf")
# returns: zort 接着,我准备了一个字段对象(fooSpec),对两个mock方法设置了返回值,为doFoo()设置了side_effect(第21行)。我将fooSpec传入configure_mock(),注意fooSpec带有前缀'**'(第22行)。现在调用callFoo()结果返回“narf”。调用doFoo(),无论输入什么,引发StandardError 信号(行24~27)。如果我修改了fooSpec,设置doFoo()的side_effect的值为None,当我调用doFoo()时,将得到结果“zort”(29~32行)。 |
The next method, mock_add_spec() , lets you add new attributes to the mock object. Its function is similar to the constructor argument spec, exceptmock_add_spec() works on an existing object, and it "erases" those attributes set by the constructor. The method takes two arguments: the attribute spec (aSpec ) and a spec_set flag (aFlag ). Again, the spec may be a list of strings or it may be a class. The added attributes are read-only by default, but passing a True to the spec_set flag make those same attributes writable. Listing Sixteen demonstrates mock_add_spec() in action. The mock object (mockFoo ) starts with attributes coming from class Foo (line 25). When I access two of the attributes (_fooValue and callFoo() ), I get a result confirming their presence (lines 29-32) Listing Sixteen from mock import Mock
# The class interfaces
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
class Bar(object):
# instance properties
_barValue = 456
def callBar(self):
pass
def doBar(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo._fooValue
# returns <Mock name='mock._fooValue' id='2788112'>
print mockFoo.callFoo()
# returns: <Mock name='mock.callFoo()' id='2815376'>
# add a new spec attributes
mockFoo.mock_add_spec(Bar)
print mockFoo
# returns: <Mock spec='Bar' id='491088'>
print mockFoo._barValue
# returns: <Mock name='mock._barValue' id='2815120'>
print mockFoo.callBar()
# returns: <Mock name='mock.callBar()' id='4544368'>
print mockFoo._fooValue
# raises: AttributeError: Mock object has no attribute '_fooValue'
print mockFoo.callFoo()
# raises: AttributeError: Mock object has no attribute 'callFoo' Then, I use mock_add_spec() to add class Bar to mockFoo (line 35). The mock object now assumes the attributes declared in class Bar (lines 39-42). If I access any Foo attribute, the mock object raises an AttributeError to signal their absence (lines 44-47). |
译者信息 下一个方法mock_add_spec()让你向mock对象添加新的属性。除了mock_add_spec()工作在一个已存在的对象上之外,它的功能类似于构造器的spec参数。它擦除了一些构造器设置的属性。这个方法带有两个参数:spec属性(aSpec)和spc_set标志(aFlag)。再次,spce可以是字符串列表或者是类。已添加的属性缺省状态是只读的,但是通过设置spec_set标志为True,可以让属性可写。 Listing Sixteen演示了mock_add_spec()的运用。mock对象mockFoo开始的属性来自于类Foo(第25行)。当我访问两个属性(_fooValue和callFoo())时,我得到结果确认他们是存在的(29~32行)。 Listing Sixteen from mock import Mock
# The class interfaces
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
class Bar(object):
# instance properties
_barValue = 456
def callBar(self):
pass
def doBar(self, argValue):
pass
# create the mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo._fooValue
# returns <Mock name='mock._fooValue' id='2788112'>
print mockFoo.callFoo()
# returns: <Mock name='mock.callFoo()' id='2815376'>
# add a new spec attributes
mockFoo.mock_add_spec(Bar)
print mockFoo
# returns: <Mock spec='Bar' id='491088'>
print mockFoo._barValue
# returns: <Mock name='mock._barValue' id='2815120'>
print mockFoo.callBar()
# returns: <Mock name='mock.callBar()' id='4544368'>
print mockFoo._fooValue
# raises: AttributeError: Mock object has no attribute '_fooValue'
print mockFoo.callFoo()
# raises: AttributeError: Mock object has no attribute 'callFoo' 然后,我使用mock_add_spec()方法添加类Bar到mockFoo(第35行)。mock对象现在的属性已声明在类Bar中(39~42行)。如果我访问任何Foo属性,mock对象将引发AttributeError 信号,表示他们不存在(44~47行)。 |
The last method, resetMock() , puts the mock object back to its pre-test state. It clears the mock's call statistics and asserts. It does not clear thereturn_value and side_effect properties for both mock and its method attributes. Do this to reuse the mock and avoid the overhead of creating another mock. Finally, you can assign a return value or side-effect to each method attribute. This you do through the accessors return_value and side_effect . For example, to make the method callFoo() return a value of "narf ", use thereturn_value accessor as follows: mockFoo.callFoo.return_value = "narf" To give callFoo( ) the side-effect of TypeError , use the side_effect accessor as follows: mockFoo.callFoo.side_effect = TypeError To clear the side-effect, pass None to the accessor: mockFoo.callFoo.side_effect = None You can also use the same two accessors to change how the mock object responds to a factory call. |
译者信息 最后一个方法resetMock(),恢复mock对象到测试前的状态。它清除了mock对象的调用统计和断言。它不会清除mock对象的return_value和side_effect属性和它的方法属性。这样做是为了重新使用mock对象避免重新创建mock的开销。 最后,你能给每个方法属性分配返回值或者side-effect。你能通过return_value和side_effect访问器做到这些。例如,按如下的语句通过return_value访问器设置方法callFoo()的返回值为"narf": mockFoo.callFoo.return_value = "narf" 按如下的语句通过side_effect访问器 设置方法callFoo()的side-ffect为TypeError mockFoo.callFoo.side_effect = TypeError 传入None清除side-effect mockFoo.callFoo.side_effect = None 你也可以用这个两个相同的访问器改变mock对象对工厂调用的响应值。 |
Statistics with a Mock The last set of methods consists of accessors that track any calls made to a mock object. The accessor called returns a True when the mock gets a factory call, False otherwise. Consider the code in Listing Seventeen. After I create mockFoo , the called accessor returns a False result (lines 19-20). If I do a factory call, it returns a True result (lines 22-23). But what if I create a second mock object, then invoke a mocked method (callFoo() , line 30)? In that case, the called accessor will only give a False result (lines 31-32). Listing Seventeen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.called
# returns: False
mockFoo()
print mockFoo.called
# returns: True
mockFoo = Mock(spec = Foo)
print mockFoo.called
# returns: False
mockFoo.callFoo()
print mockFoo.called
# returns: False The accessor call_count gives the number of times a mock object gets a factory call. Consider the code in Listing Eighteen. After I create mockFoo ,call_count gives the expected result of 0 (lines 19-20). When I make a factory call to mockFoo , call_count increases by 1 (lines 22-24). When I invoke the mocked method callFoo() , call_count remains unchanged (lines 26-28). If I do a second factory call, call_count should increase by 1 more. Listing Eighteen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.call_count
# returns: 0
mockFoo()
print mockFoo.call_count
# returns: 1
mockFoo.callFoo()
print mockFoo.call_count
# returns: 1 |
译者信息 Mock统计 最后一套方法包含跟踪mock对象所做的任意调用的访问器。当mock对象获得工厂调用时,访问器called返回True,否则返回False。查看Listing Seventeen中的代码,我创建了mockFoo之后,called访问器返回了结果False(19~20行)。如果我做了一个工厂调用,它将返回结果True(22~23行)。但是如果我创建了第二个mock对象,然后调用了mock方法callFoo()(第30行)?在这个例子中,called访问器仅仅放回了False结果(31~32行)。 Listing Seventeen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.called
# returns: False
mockFoo()
print mockFoo.called
# returns: True
mockFoo = Mock(spec = Foo)
print mockFoo.called
# returns: False
mockFoo.callFoo()
print mockFoo.called
# returns: False 访问器call_count给出了mock对象被工厂调用的次数。查看Listing Eighteen中的代码。我创建mockFoo之后,call_count给出的期望结果为0(19~20行)。当我对mockFoo做了一个工厂调用时,call_count增加1(22~24行)。当我调用mock方法callFoo()时,call_count没有改变(26~28行)。如果我做了第二次工厂调用call_count将再增加1。 Listing Eighteen from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo)
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.call_count
# returns: 0
mockFoo()
print mockFoo.call_count
# returns: 1
mockFoo.callFoo()
print mockFoo.call_count
# returns: 1 |
The accessor call_args returns the arguments used in a factory call. Listing Nineteen demonstrates its action. For a newly created mock object (mockFoo ), the call_args accessor gives a result of None (lines 17-21). If I make a factory call, passing "zort" for input, call_args reports it as"call('zort')" (line 23-25). Note the call keyword in the result. For a second factory call, without input, call_args returns "call()" (lines 27-29). A third factory call, with "troz" for input, gives the result "call('troz')" from call_args (lines 31-33). But when I invoke the mocked methodcallFoo() , the call_args accessor still returns "call('troz')" (lines 35-37). Listing Nineteen #!/usr/bin/python
from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo, return_value = "narf")
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.call_args
# returns: None
mockFoo("zort")
print mockFoo.call_args
# returns: call('zort')
mockFoo()
print mockFoo.call_args
# returns: call()
mockFoo("troz")
print mockFoo.call_args
# returns: call('troz')
mockFoo.callFoo()
print mockFoo.call_args
# returns: call('troz') The accessor call_args_list also reports the arguments used in a factory call. But while call_args returns the most recent arguments,call_args_list returns a list, with the first item being the earliest argument. Listing Twenty shows the accessor in action, using the same code in Listing Nineteen. |
译者信息 访问器call_args返回工厂调用已用的参数。Listing Nineteen演示了它的运用。对于新创建的mock对象(mockFoo),call_args访问器返回结果为None(17~21行)。如果我做了一个工厂调用,在输入中传入"zort",call_args报告的结果为call('zort')(23~25行)。注意结果中的call关键字。对于第二个没有输入的工厂调用,call_args返回call()(27~29行)。第三个工厂调用,输入“troz”,call_args给出结果为call('troz')(31~33行)。但是当我调用mock方法callFoo()时,call_args访问器仍然返回call('troz')(35~37行)。 Listing Nineteen #!/usr/bin/python
from mock import Mock
# The mock object
class Foo(object):
# instance properties
_fooValue = 123
def callFoo(self):
print "Foo:callFoo_"
def doFoo(self, argValue):
print "Foo:doFoo:input = ", argValue
# create the first mock object
mockFoo = Mock(spec = Foo, return_value = "narf")
print mockFoo
# returns <Mock spec='Foo' id='507120'>
print mockFoo.call_args
# returns: None
mockFoo("zort")
print mockFoo.call_args
# returns: call('zort')
mockFoo()
print mockFoo.call_args
# returns: call()
mockFoo("troz")
print mockFoo.call_args
# returns: call('troz')
mockFoo.callFoo()
print mockFoo.call_args
# returns: call('troz') 访问器call_args_list 也报告了工厂调用中已使用的参数。但是call_args返回最近使用的参数,而call_args_list返回一个列表,第一项为最早的参数。Listing Twenty显示了这个访问的的运用,使用了和Listing Nineteen相同的代码。 |