Mobile version of this pageSee you at PyCon 2008
Next:
apple.com/store doesn't work in Firefox (on Linux)
Related blogs
Google London Automation Test conference (part II)Google London Automation Test conference
See you at PyCon 2008
Now I have a Gmail account
Gmail spam filter
IssueTrackerProduct 0.7 released
Related by category
Mocking a Python standard library
pycon, gheorghiu, unit tests, automated testing, mocking, monkey, monkey-patching, unit/integration, pop3
14th of March 2008
Here's one of many things I've learnt today at PyCon. Inspired by code that Grig Gheorghiu showed in his slides on automated testing, you can monkey patch a standard library that your application is using in your unit tests to, in my case, mock a remote service without having to run a server. I've done lots of monkey-patching in Zope but then I've only been monkey patching individual methods or attributes of imported classes. This is very similar to that. Here's what my application does:
class MyZopeApp(...):
def check4mail(self, hostname, port, user, pwd):
connection = POP3(hostname, port=port)
...download emails and process them...
Adjacent to this I have a unit/integration test that looks like this:
def test_check4mail(self):
# monkey patch!
# note that this imports a module, not a class
from Products.IssueTrackerProduct import IssueTracker
FakePOP3.files = ('test1.email',)
IssueTracker.POP3 = FakePOP3
# now check what happens when check4mail() is run
result = self.folder.tracker.check4mail()
assert ...
Now for the mock. The mock is a fake POP3 class that instead of getting its data from the network reads local filesystem files. Here's what the code for FakePOP3 is:
class FakePOP3(POP3):
username = 'test'
password = 'test'
files = []
def __init__(self, hostname, port=110):
self.hostname = hostname
self.port = port
def getwelcome(self):
return "Welcome to fake account"
def user(self, user):
if user != self.username:
raise error_proto("Wrong username.")
def pass_(self, pswd):
if pswd != self.password:
raise error_proto("Wrong password.")
def list(self, which=None):
# eg. ('+OK 4 messages:', ['1 71017', '2 2201', '3 7723', '4 44152'], 34)
files = self.files
responses = []
for i, f in enumerate(files):
responses.append('%s %s' % (i+1, os.stat(f)[stat.ST_SIZE]))
return ('+OK %s messages:' % len(files), responses, None)
def retr(self, which):
# ['response', ['line', ...], octets]
filename = self.files[which-1]
return ('response', open(filename, 'r').xreadlines(), None)
def quit(self):
pass
That's it! That's how you fake a POP3 server without having to run an actual mock server which could have been a solution.







Save this page in del.icio.us
A less advanced alternative is minimock by Ian Bicking:
http://blog.ianbicking.org/minimock.html