[Python-Dev] How far to go with user-friendliness

Florian Bruhin me at the-compiler.org
Mon Jul 20 19:35:47 CEST 2015


* Ron Adam <ron3200 at gmail.com> [2015-07-20 12:57:08 -0400]:
> >It's "unsafe" because tests which:
> >
> >1) are using the assert_* methods of a mock, and
> >2) where the programmer did a typo (assert_called() instead of
> >    assert_called_with() for example)
> >
> >do silently pass.
> 
> And further down, you say...
> 
> >Compare it with the behavior of a normal object - if you call a method
> >which doesn't exist, it raises AttributeError.
> >
> >This isn't possible with Mock objects, as they are designed to support
> >*any*  call, and you can check the calls have happened after the fact.
> 
> 
> And the docs say...
> 
> """
> spec: This can be either a list of strings or an existing object (a class or
> instance) that acts as the specification for the mock object. If you pass in
> an object then a list of strings is formed by calling dir on the object
> (excluding unsupported magic attributes and methods). Accessing any
> attribute not in this list will raise an AttributeError.
> """
> 
> So calling a method that doesn't exist on a mocked object will raise an
> AttributeError if it is given a spec.
> 
> But if you don't give it a spec, then a mispelling of *any* method will pass
> silently.  So it's not a problem limited to "assert" methods.
> 
> It seems the obvious and best solution is to always use a spec.

I agree - I always use mocks with autospec/spec, and I recommend doing
that - I actually plan to write a plugin for pylint to enforce this.

Still mistyping the assert methods seems to be a common issue, since
(according to some other mail) a couple of bugs in OpenStack were
found this way.

But yeah - if your code under test has a typo, and you don't use
spec/autospec, you might not notice as well - though in my experience
you *usually* do, since the returned mock object doesn't behave in the
way you expect it to.

But yeah - always using (auto)spec is probably the best solution.

> >>> m.assert_me()
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "/media/hda2/home/ra/Dev/python-dev/python3.5/cpython-master/Lib/unittest/mock.py",
> line 583, in __getattr__
>     raise AttributeError(name)
> AttributeError: assert_me
> 
> 
> Why is AttributeError raised here?  Why are methods beginning with assert
> special?  (or "unsafe")

Some things I can think of:

- It's more likely that you use assert_called() instead of
  assert_called_with() accidentally than that you do a typo in your
  code under test.

- If you do a typo in your code under test, a linter is more likely to
  find it than with mocks, because of their nature.

- Other tests (even if they're manual ones) should probably discover
  the typo in your real code. The always-passing assert won't.

Florian

-- 
http://www.the-compiler.org | me at the-compiler.org (Mail/XMPP)
   GPG: 916E B0C8 FD55 A072 | http://the-compiler.org/pubkey.asc
         I love long mails! | http://email.is-not-s.ms/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/python-dev/attachments/20150720/d842bd7f/attachment.sig>


More information about the Python-Dev mailing list