Export to GitHub

mock - issue #105

Subclassing Mock uses subclass for attributes


Posted on Jul 18, 2011 by Happy Lion

What steps will reproduce the problem? 1. class Foo(Mock): pass 2. f = Foo() print type(f.bar.baz)

What is the expected output? What do you see instead?

expected: <class 'Mock'>

instead: <class 'mock.Foo'> (interesting aside - the class name isn't even correct!)

What version of the product are you using? On what operating system?

>>> print mock.version 0.7.2

Please provide any additional information below.

This is particularly problematic when you want to add some functionality to a mock, but that functionality is not appropriate (and causes errors) when applied to its attributes. In my case, I'm defining an adapter (http://twistedmatrix.com/documents/11.0.0/api/twisted.python.components.html) for my subclass, but properties of its instances should not be adaptable.

Comment #1

Posted on Jul 18, 2011 by Helpful Monkey

Interesting.

Ensuring that mock attributes are of the same type as the parent was a deliberate decision. If you create a subclass of Mock with helper methods then having those available on all attributes is very useful. This is an unfortunate side effect of that decision.

I'll see if I can find a way to get the best of both worlds (probably a method for subclasses to override to prevent attributes using the parent class).

Comment #2

Posted on Jul 18, 2011 by Helpful Monkey

And as a note the name of the class is not incorrect. Working out why is left as an exercise for the reader... :-)

It's likely that any fix for this issue will be in 0.8 rather than a new 0.7 release, because I'll probably fix it with a new feature rather than reverting the attribute / subclass interaction.

Comment #3

Posted on Jul 18, 2011 by Helpful Monkey

Actually, you can already achieve this by overriding _get_child_mock:

{{{

class Subclass(Mock): def _get_child_mock(self, **kwargs): return MagicMock(**kwargs)

{{{

This will be used for return value and attributes. I'll add a test for this so that I don't break it in the future and add it as an example to the docs.

Comment #4

Posted on Jul 18, 2011 by Happy Lion

That's what I've done (overriding _get_child_mock), but that leading underscore suggests it's not the best solution. Maybe just making that method public (or renaming) would fix this?

Comment #5

Posted on Jul 18, 2011 by Helpful Monkey

It's not a straightforward situation though - making it a public api would imply you could call it directly. Which you shouldn't. I think documenting it as the right way to solve this particular problem is the best approach.

See:

http://www.voidspace.org.uk/python/weblog/arch_d7_2011_07_16.shtml#e1221

This will be in the mock examples page from the 0.8 release.

For what its worth this is an api issue I've come across several times before - how to make it clear that a method is not part of the external public api but can be overridden by subclasses.

Status: WontFix

Labels:
Type-Enhancement Priority-Medium