21
21/10/2008
Pylons, xmlrpc and doctest
How to make some doctests with pylons and an xmlrpc controller
I m actually developping some application around XMLRPC protocol at work.
We are using Pylons for the framework part, and i played this afternoon at setting up some testing environnement for doing doctests.
This test is a proof of concept, it 's code extracted from our internal application, it's just a starter for you. The whole is working with some tweaks.
controllers/mycontroller.py, a simple controller doing simple stuff
class MyController(XMLRPCController):
"""controller."""
def index(self):
return '\_o<'
lib/base.py, Please add the XMLRPCController import
lib/base.py:from pylons.controllers import WSGIController, XMLRPCController
Then, we are setted up to continue with tests
First of all, the doctest boilerplate:
tests/test_doctest_files.py
import doctest
from doctest import DocFileSuite
from myproject.tests import setUp, tearDown
flags = (doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_ONLY_FIRST_FAILURE)
def test_suite():
return DocFileSuite(
"test.txt",
setUp = setUp,
tearDown = tearDown,
optionflags = flags
)
setUp and tearDown will have a central place as they are intialising the application.
As we can't use paste.fixture.TestApp objects with XMLRPC because it does not bind everywhere, the idea is
- launch the server somewhere in a thread
- use it later, as usual throught xmlrplib.
- We will even declare it as a global to ease the doctests writings.
- We also add a wrapper to url_for to return the host to bind to.
import os
import sys
import re
import threading
from ConfigParser import ConfigParser
from unittest import TestCase
import paste.fixture
import paste.script.appinstall
from paste.deploy import loadapp
from paste.httpserver import serve
from routes.util import url_for
here_dir = os.path.dirname(os.path.abspath(__file__))
conf_dir = os.path.dirname(os.path.dirname(here_dir))
test_file = os.path.join(here_dir, 'test.ini')
cmd = paste.script.appinstall.SetupCommand('setup-app')
cmd.run([test_file])
def setUp(test, *args, **kwargs):
print "\t-----------------------------------------------------------------"
print "\t--- Setting up database test environment, please stand by. ---"
print "\t-----------------------------------------------------------------"
config = ConfigParser()
config.read(
os.path.join(os.path.dirname(sys.argv[0]), '..', 'etc', 'config.ini')
)
infos = ConfigParser()
infos.read(test_file)
sinfos = infos._sections['server:main']
wsgiapp = loadapp('config:test.ini', relative_to = here_dir)
server = test.globs['server'] = serve(wsgiapp,
t = threading.Thread(target=server.serve_forever)
t.setDaemon(True)
t.start()
test.globs['app'] = paste.fixture.TestApp(wsgiapp)
def url_for_wrapper(*args, **kwargs):
lkwargs = {'protocol': 'http' ,'host': "%s:%s" % (server.server_name, server.server_port)}
lkwargs.update(kwargs)
return url_for(*args, **lkwargs)
test.globs['url_for'] = url_for_wrapper
test.globs['url_for_orig'] = url_for
def tearDown(test):
test.globs['server'].server_close()
class TestController(TestCase):
def __init__(self, *args, **kwargs):
wsgiapp = loadapp('config:test.ini', relative_to = here_dir)
self.app = paste.fixture.TestApp(wsgiapp)
TestCase.__init__(self, *args, **kwargs)
And finally, letz play with our doctest
tests/text.txt
>>> create_url = url_for(controller='mycontroller') >>> import xmlrpclib >>> s = xmlrpclib.Server(create_url) >>> s.index() '\\_o<'


