Zach Hirsch
Zach Hirsch

Reputation: 26101

Using mocking to test derived classes in Python

I have code that looks like this:

import xmlrpclib

class Base(object):
    def __init__(self, server):
        self.conn = xmlrpclib.ServerProxy(server)

    def foo(self):
        return self.conn.do_something()

class Derived(Base):
    def foo(self):
        if Base.foo():
            return self.conn.do_something_else()

How should I use mocking to test the behavior of the Derived class? I don't want to assume that whatever the XML-RPC connection talks to will actually exist, but I feel like mocking the xmlrpclib module requires too much knowledge of the implementation of the Base class (which I have other tests for).

Or, I guess, should I even use mocking to test this? If not, how would you test it?

Upvotes: 4

Views: 1934

Answers (2)

Pavel Repin
Pavel Repin

Reputation: 30943

With some trivial refactoring (call to do_something_else is extracted), you can test Derived.foo logic without needing to "know" about XMLRPC.

import xmlrpclib

class Base(object):
    def __init__(self, server):
        self.conn = xmlrpclib.ServerProxy(server)

    def foo(self):
        return self.conn.do_something()

class Derived(Base):
    def foo(self):
        if Base.foo(self):
            return self._bar()
    def _bar(self):
        # moved to its own method so that you
        # you can stub it out to avoid any XMLRPCs
        # actually taking place.
        return self.conn.do_something_else()

import mox

d = Derived('http://deep-thought/unanswered/tagged/life+universe+everything')

m = mox.Mox()
m.StubOutWithMock(Base, 'foo')
m.StubOutWithMock(d, '_bar')
Base.foo(d).AndReturn(True)
d._bar() # Will be called becase Boo.foo returns True.
m.ReplayAll()

d.foo()

m.UnsetStubs()
m.VerifyAll()

Alternatively or even preferably, you may extract the call to do_something_else into bar method on Base. Which makes sense, if we agree that Base encapsulates all your XMLRPC actions.

The example uses pymox mocking library, but the gist of it stays the same regardless of your mocking style.

Upvotes: 3

Ryan Ginstrom
Ryan Ginstrom

Reputation: 14121

You could create a fake ServerProxy class, and substitute that for testing.

Something like this:

class FakeServerProxy(object):
    def __init__(self, server):
        self.server = server
    def do_something(self):
        pass
    def do_something_else(self):
        pass

def test_derived():
    xmlrpclib.ServerProxy = FakeServerProxy
    derived = Derived(None)
    derived.foo()

Upvotes: 4

Related Questions