Thanks for your prompt attention to this.<br><br>I have actually noticed some interesting usage patterns when utilizing mock; it seems like there are two types of functionality I am trying to mock, the first is where a module acts as a wrapper for a class or module which performs some sort of external work. In this case I find myself calling assert_called_with quite a bit because I want the external module to have been directed to do something specific at the completion of the test; failing to do so constitutes a test failure. The second type is when another module acts as a set of utilities for the class I'm testing. I still want to make sure that the module is called correctly (i.e. not in a way that will cause an error at runtime), but the class being tested has more autonomy to decide which functions are called and how in order to get done whatever it needs to be doing. Specifying all the function calls exactly here makes the test too restrictive and will cause the test code to need to be re-written when something trivial about the class being tested changes.<br>
<br>The second scenario is where I envisioned mocksignature=True coming in handy, but it's still not 100% where I want it to be, seemingly due to the limitations of python. I like python a lot but one has to accept that it's simply a "dangerous" language in which it's hard to make guarantees about whether or not code will work properly, even if one is willing to spend a lot of time writing tests.<br>
<br> -W.W.<br><br><br><div class="gmail_quote">On Fri, Nov 12, 2010 at 7:26 AM, Michael Foord <span dir="ltr"><<a href="mailto:fuzzyman@voidspace.org.uk">fuzzyman@voidspace.org.uk</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000"><div class="im">
On 02/11/2010 17:02, WW wrote:
</div><div class="im"><blockquote type="cite">You may have overlooked this from my earlier e-mail:<br>
<br>
Here's a small test case that produces the error in Python 2.6,
CentOS 5.5:<br>
<br>
</blockquote>
<br></div>
I finally found time to track this down. The cause is due to the way
attributes are looked up (you're patching an *instance method* and
methods don't actually live on instances they are fetched from the
class when the method is looked up).<br>
<br>
Anyway, it's now fixed in the repository.<br>
<br>
All the best,<br><font color="#888888">
<br>
Michael</font><div><div></div><div class="h5"><br>
<br>
<blockquote type="cite">
<div style="font-family: monospace;">
<ol>
<li>
<div>from mock import patch</div>
</li>
<li>
<div> </div>
</li>
<li>
<div>class tc<span>(</span>object<span>)</span>:</div>
</li>
<li>
<div> def meth<span>(</span>a, b, c<span>)</span>:</div>
</li>
<li>
<div> pass</div>
</li>
<li>
<div> </div>
</li>
<li>
<div>g = tc<span>(</span><span>)</span></div>
</li>
<li>
<div> </div>
</li>
<li>
<div>@patch.object<span>(</span>g, 'meth',
mocksignature=True<span>)</span></div>
</li>
<li>
<div>def test_g<span>(</span>patched<span>)</span>:</div>
</li>
<li>
<div> g.meth<span>(</span><span>1</span><span>)</span></div>
</li>
<li>
<div> </div>
</li>
<li>
<div>test_g<span>(</span><span>)</span></div>
</li>
</ol>
</div>
<br>
<br>
<div class="gmail_quote">On Tue, Nov 2, 2010 at 1:00 PM, Michael
Foord <span dir="ltr"><<a href="mailto:fuzzyman@voidspace.org.uk" target="_blank">fuzzyman@voidspace.org.uk</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div> On 02/11/2010 16:57, WW wrote:
<blockquote type="cite">Replacing "@patch.object(g,
'meth', mocksignature=True)" with "@patch('%s.g.meth' %
__name__, mocksignature=True)" produces the same error.
Am I using this wrong?<br>
</blockquote>
<br>
</div>
Is this the same traceback you posted earlier?
<div><br>
<br>
'SentinelObject' object has no attribute '__call__'<br>
<br>
</div>
Can you reproduce this with a minimal example? I've never
seen that particular issue before.
<div><br>
<br>
<blockquote type="cite"><br>
Thanks for the clarification regarding spec vs
mocksignature. So if I wanted to do both (a mock class
that raises attribute errors when invalid attributes are
accessed, but actual method attributes return methods
that enforce the correct number of parameters), do I
have to set that up manually, or does spec use
mocksignature internally when returning attribute
values?<br>
<br>
</blockquote>
<br>
</div>
Using mocksignature changes the way that you access the
mock. As the methods are replaced with 'real function
objects' not mock objects as they normally are, you have to
do it explicitly. You could create a utility function to
auto patch out a mock with mocked-signatures.<br>
<br>
spec is purely about checking attribute access is valid.
<div>
<div><br>
<br>
All the best,<br>
<br>
Michael Foord<br>
<br>
<blockquote type="cite">Thanks again...<br>
<br>
<div class="gmail_quote">On Tue, Nov 2, 2010 at 12:49
PM, Michael Foord <span dir="ltr"><<a href="mailto:fuzzyman@voidspace.org.uk" target="_blank">fuzzyman@voidspace.org.uk</a>></span>
wrote:<br>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div> On 02/11/2010 16:43, WW wrote:
<blockquote type="cite">On Tue, Nov 2, 2010 at
12:17 PM, Michael Foord <span dir="ltr"><<a href="mailto:fuzzyman@voidspace.org.uk" target="_blank">fuzzyman@voidspace.org.uk</a>></span>
wrote:<br>
<div class="gmail_quote">
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div> On 02/11/2010 15:34, WW wrote:
<blockquote type="cite">Hello,<br>
<br>
This is my first time using the
python mock library and I'm a
little confused. I'd like to
provide some guarantees that my
mocks are being called with the
correct number of arguments. The
documentation seems to indicate
there are two ways to do this,
"spec" and "mocksignature", but
it's a little unclear to me what
the difference is supposed to be
between them.<br>
<br>
I find myself using the
@patch.object decorator almost all
the time, because the modules I'm
testing use a lot of top-level
functions from modules they've
imported. When I do something
like this:<br>
<br>
@patch.object(somemodule,
'somemethod', spec=True)<br>
<br>
</blockquote>
<br>
</div>
You should still be able to use patch
with a named function (as a string).
See the other replies for an example.</div>
</blockquote>
<div bgcolor="#ffffff" text="#000000">
<div><br>
Does this work if I'm trying to patch
a global variable rather than a
function in another module?<br>
</div>
</div>
</div>
</blockquote>
<br>
</div>
You mean a global variable in the current
module? If so then still yes.<br>
<br>
@patch('%s.function' % __name__,
mocksignature=True)<br>
def test_something(self, mockfunction):<br>
...
<div><br>
<br>
<br>
<blockquote type="cite">
<div class="gmail_quote">
<div bgcolor="#ffffff" text="#000000">
<div> <br>
</div>
</div>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div>
<blockquote type="cite"> It doesn't
seem to have any effect; I can
call somemodule.somemethod with
any combination of invalid
arguments and no exceptions are
thrown. </blockquote>
<br>
</div>
Using spec doesn't protect you against
being called with invalid arguments.
You should get an error when you
validate that the calls were made
correctly when you call
'assert_called_with'.
<div><br>
</div>
</div>
</blockquote>
<div bgcolor="#ffffff" text="#000000">
<div><br>
assert_called_with is fine if I know
the exact values I want the function
to be called with, but I'm just trying
to make sure that a function was
called with the correct number of
arguments. If spec can't do this,
then what is spec supposed to be used
for? I'm still unclear as to what the
difference is between spec and
mocksignature and why both exist.<br>
</div>
</div>
</div>
</blockquote>
<br>
</div>
spec is not for mocking functions (mocksignature
is). Spec is for mocking out classes / objects
to check that only methods / attributes that
exist on the spec object are used. Accessing
other attributes will raise an AttributeError.
<div>
<div><br>
<br>
All the best,<br>
<br>
Michael Foord<br>
<br>
<blockquote type="cite">
<div class="gmail_quote">
<div bgcolor="#ffffff" text="#000000">
<div> </div>
</div>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div>
<blockquote type="cite"> However,
when I do:<br>
<br>
@patch.object(somemodule,
'somemethod',
mocksignature=True)<br>
<br>
I get:<br>
<br>
Traceback (most recent call
last):<br>
File "/usr/lib/python2.6/site-
<div>packages/mock-0.7.0b3-py2.6.egg/mock.py",
line 485, in patched<br>
arg = patching.__enter__()<br>
File
"/usr/lib/python2.6/site-packages/mock-0.7.0b3-py2.6.egg/mock.py",
line 536, in __enter__<br>
new_attr =
mocksignature(original, new)<br>
File
"/usr/lib/python2.6/site-packages/mock-0.7.0b3-py2.6.egg/mock.py",
line 140, in mocksignature<br>
signature, func =
_getsignature(func, skipfirst)<br>
File
"/usr/lib/python2.6/site-packages/mock-0.7.0b3-py2.6.egg/mock.py",
line 87, in _getsignature<br>
func = func.__call__<br>
AttributeError:
'SentinelObject' object has no
attribute '__call__'<br>
<br>
</div>
</blockquote>
<br>
</div>
This is weird. The traceback implies
that you are trying to replace a
sentinel object using mocksignature
(and sentinels don't have signatures
to mock). Either that or it is a
bug. I'll create a simple test case
here (but this functionality *is*
tested), but it looks like something
is not quite setup how you expect.</div>
</blockquote>
<div bgcolor="#ffffff" text="#000000">
<div><br>
Here's a small test case that
produces the error in Python 2.6,
CentOS 5.5:<br>
<br>
<div style="font-family: monospace;">
<ol>
<li>
<div>from mock import patch</div>
</li>
<li>
<div> </div>
</li>
<li>
<div>class tc<span>(</span>object<span>)</span>:</div>
</li>
<li>
<div> def meth<span>(</span>a,
b, c<span>)</span>:</div>
</li>
<li>
<div> pass</div>
</li>
<li>
<div> </div>
</li>
<li>
<div>g = tc<span>(</span><span>)</span></div>
</li>
<li>
<div> </div>
</li>
<li>
<div>@patch.object<span>(</span>g,
'meth', mocksignature=True<span>)</span></div>
</li>
<li>
<div>def test_g<span>(</span>patched<span>)</span>:</div>
</li>
<li>
<div> g.meth<span>(</span><span>1</span><span>)</span></div>
</li>
<li>
<div> </div>
</li>
<li>
<div>test_g<span>(</span><span>)</span></div>
</li>
</ol>
</div>
<br>
</div>
</div>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<div> <br>
All the best,<br>
<br>
Michael Foord<br>
</div>
</div>
</blockquote>
<div bgcolor="#ffffff" text="#000000">
<div><br>
Likewise.<br>
</div>
</div>
<blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div bgcolor="#ffffff" text="#000000">
<blockquote type="cite">
<div>
<div>What am I missing here?<br>
<br>
Thanks for your help.</div>
</div>
<pre><fieldset></fieldset>
_______________________________________________
testing-in-python mailing list
<div><a href="mailto:testing-in-python@lists.idyll.org" target="_blank">testing-in-python@lists.idyll.org</a>
<a href="http://lists.idyll.org/listinfo/testing-in-python" target="_blank">http://lists.idyll.org/listinfo/testing-in-python</a>
</div></pre>
</blockquote>
<div> <br>
<br>
<pre cols="72">--
<a href="http://www.voidspace.org.uk/" target="_blank">http://www.voidspace.org.uk/</a></pre>
</div>
</div>
</blockquote>
</div>
<br>
</blockquote>
<br>
<br>
</div>
</div>
<pre cols="72"><div><div>--
<a href="http://www.voidspace.org.uk/" target="_blank">http://www.voidspace.org.uk/</a></div></div>
READ CAREFULLY. By accepting and reading this email you agree,
on behalf of your employer, to release me from all obligations
and waivers arising from any and all NON-NEGOTIATED agreements,
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,
confidentiality, non-disclosure, non-compete and acceptable use
policies (”BOGUS AGREEMENTS”) that I have entered into with your
employer, its partners, licensors, agents and assigns, in
perpetuity, without prejudice to my ongoing rights and privileges.
You further represent that you have the authority to release me
from any BOGUS AGREEMENTS on behalf of your employer.
</pre>
</div>
</blockquote>
</div>
<br>
</blockquote>
<br>
<br>
<pre cols="72">--
<a href="http://www.voidspace.org.uk/" target="_blank">http://www.voidspace.org.uk/</a>
READ CAREFULLY. By accepting and reading this email you agree,
on behalf of your employer, to release me from all obligations
and waivers arising from any and all NON-NEGOTIATED agreements,
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,
confidentiality, non-disclosure, non-compete and acceptable use
policies (”BOGUS AGREEMENTS”) that I have entered into with your
employer, its partners, licensors, agents and assigns, in
perpetuity, without prejudice to my ongoing rights and privileges.
You further represent that you have the authority to release me
from any BOGUS AGREEMENTS on behalf of your employer.
</pre>
</div>
</div>
</div>
</blockquote>
</div>
<br>
</blockquote>
<br>
<br>
<pre cols="72">--
<a href="http://www.voidspace.org.uk/" target="_blank">http://www.voidspace.org.uk/</a>
READ CAREFULLY. By accepting and reading this email you agree,
on behalf of your employer, to release me from all obligations
and waivers arising from any and all NON-NEGOTIATED agreements,
licenses, terms-of-service, shrinkwrap, clickwrap, browsewrap,
confidentiality, non-disclosure, non-compete and acceptable use
policies (”BOGUS AGREEMENTS”) that I have entered into with your
employer, its partners, licensors, agents and assigns, in
perpetuity, without prejudice to my ongoing rights and privileges.
You further represent that you have the authority to release me
from any BOGUS AGREEMENTS on behalf of your employer.
</pre>
</div></div></div>
</blockquote></div><br>