Closed GoogleCodeExporter closed 9 years ago
@fuzzyman - what are your thoughts about this? Do you think this is something
that would be useful to the masses or do you think this should belong in a
separate extension library somewhere outside of mock, or lastly do you think
this should just plain not exist?
Original comment by mattj.mo...@gmail.com
on 1 Jul 2011 at 2:38
I don't understand why you would assert the result, when the result of a
chained mock call will be whatever you set it to be?
Original comment by fuzzyman
on 17 Jul 2011 at 1:08
Original comment by fuzzyman
on 17 Jul 2011 at 1:08
Take a look at this example:
def somefunc():
return SomeThing('x').first('1').second(2).third().final()
If i want a test to assert that I called SomeThing with 'x', first with '1',
second with 2 third with nothing and final with nothing, then return whatever
final returns I would have to do the following things in my test:
SomeThing.return_value.first.return_value.second.return_value.third.return_value
.final.return_value = 'What I Expect'
result = somefunc()
assert result == 'What I Expect'
assert SomeThing.call_args ...
assert SomeThing.return_value.first.call_args ...
assert SomeThing.return_value.first.return_value.second.call_args ...
assert
SomeThing.return_value.first.return_value.second.return_value.third.call_args
...
assert
SomeThing.return_value.first.return_value.second.return_value.third.return_value
.final.call_args ...
Without asserting against the result, removing the return in somefunc would not
fail the test, also chaining another function call onto the end of
final.return_value would not cause the test to fail. Also, in this scenario I
don't really care what the return_value of final is, as long as that is what
comes back from somefunc my test will pass, so I don't really even need to
explicitly set the return value if I can somehow get a hold of whatever Mock
object that return value was.
The other benefit of asserting against the return value is that currently, in
this example, if I change the chain order or add or remove anything from the
chained call I will now need to update my test in at least 2 places. Once in
the setup, once for the last assertion against final's call_args and
potentially some of the other assertions depending on how somefunc changed.
With the chained assertion checking the return value you can eliminate the
duplication between the setup and assertions (and potentially eliminate the
setup all together) of the test and it would become:
result = somefunc()
my_mock.assert_call_chain([
('first', ('1',), {}),
('second', (2,), {}),
('third', (), {}),
('final', (), {}),
], result)
Does that paint a better picture of possible uses of this?
Original comment by mattj.mo...@gmail.com
on 17 Jul 2011 at 3:01
Ok, interesting.
I agree that asserting multiple / chained calls *should* be simpler in mock.
I'm not yet convinced this is how it should look.
My current idea is to integrate the new 'call' object with the new 'mock_calls'
attribute (from issue 82 - not yet implemented) that makes all sorts of
assertions simpler.
Original comment by fuzzyman
on 17 Jul 2011 at 5:05
The new `mock_calls` functionality is implemented on head. It supports
assertions for chained calls using the (also new) `call` object.
{{{
>>> from mock import Mock, call
>>> mock = Mock()
>>> mock.foo(1).bar()().baz.beep(a=6)
<mock.Mock object at 0x519bf0>
>>> this_call = call.foo(1).bar()().baz.beep(a=6)
>>> assert mock.mock_calls == this_call.call_list()
>>> this_call
<call name='foo().bar()().baz.beep()' values=('foo().bar()().baz.beep', (),
{'a': 6})>
>>>
>>> mock = Mock()
>>> mock.a(1, 2)
<mock.Mock object at 0x519150>
>>> mock.b(3, 4)
<mock.Mock object at 0x519030>
>>> mock.c(5, 6)
<mock.Mock object at 0x519610>
>>> assert mock.mock_calls == [call.a(1, 2), call.b(3, 4), call.c(5, 6)]
}}}
It doesn't support return value assertions, so your helper function still has
that advantage. `mock_calls` tracks all calls, so it makes it simpler to make
assertions about multiple calls as well as chained calls. It also includes
calls to magic methods.
It is intended to replace `call_args_list` and `method_calls`, providing "one
place" to go and check all calls.
Original comment by fuzzyman
on 18 Jul 2011 at 12:06
Nice, I like it.
Original comment by mattj.mo...@gmail.com
on 18 Jul 2011 at 12:22
This feature request has been filled by the mock_calls and the call object for
asserting chained calls.
Original comment by fuzzyman
on 14 Nov 2013 at 11:13
Original issue reported on code.google.com by
mattj.mo...@gmail.com
on 10 Mar 2011 at 1:29Attachments: