views:

31

answers:

2

I am writing a small mocking class to do some tests.

But this class needs to support the idea of having nested attributes.

This example should provide some insight to the problem:

class Foo(object):

    def __init__(self):
        self.x = True

From the above class, we can have:

f = Foo()
f.x

I know I can add attributes falling back to __getattr__ to avoid an AttributeError, but what if I need something like this to be valid:

f = Foo()
f.x
f.x.y
f.x.y.z()

I know what to return if the object gets called as f.x.y.z() but I just need to find a way to get to z() that makes sense.

+2  A: 

You can "mock anything" by returning, on each attribute access, another instance of the "mock anything" class (which must also be callable, if you want to have the .z() part work;-).

E.g.:

class MockAny(object):

  # mock special methods by making them noops
  def __init__(self, *a, **k): pass

  # or returning fixed values
  def __len__(self): return 0

  # mock attributes:
  def getattr(self, name):
    return MockAny()

  # make it callable, if you need to
  def __call__(self, *a, **k):
    return MockAny()

The alternative, of course, is to know what it is that you're mocking (by introspection, or by some form of "declarative description", or simply by coding mock for specific things;-) rather than take the catch-all approach; but, the latter is also feasible, as you see in the above (partial) example.

Personally, I'd recommend using an existing mocking framework such as pymox rather than reinventing this particular wheel (also, the source code for such frameworks can be more instructive than a reasonably terse response on SO, like this one;-).

Alex Martelli
Right on the spot Alex. My mistake was to think that It would be OK to "build" the Mock object to get to x.y.z() when all I needed was to pass another instance of the Mock object to match that attribute. I would use a mocking framework but thought that for 2 specific calls that I am testing it would be cleaner just to implement a single mocking class.
alfredodeza
A: 

If you are calling something like f.x.y.z() in your unit tests, the chances are you're trying to test too much. Each of these nested attributes should be covered by the unit tests for their particular classes.

Take another look at your Foo class and see if you can test its own behaviour in your unit tests.

Perhaps not the answer you were looking for, but hopefully one that will help in the long run.

Johnsyweb
You are right, except for the fact that f.x.y.z() is called in the source code, not in the unittest itself. Hence the need to mock it so I can return expected behavior when that specific call is made.
alfredodeza
Generally speaking, `f` should know nothing of `z()` or even of `y`. This suggests a design flaw.
Johnsyweb