Posts tagged with “TDD”

TDD, Jython & REST (Part 3)

Sunday, 2 October, 2005

With the addition of xml validation and value checking, the testing scripts actually become somewhat useful:


> PUT http://localhost:8080/ws/user ''
    'username=testuser1&email_address=testuser1@test.com'
> GET http://localhost:8080/ws/user/testuser1
< assert status 200
< assert header Content-Type text/xml
< assert xmlschema ../web/user.xsd
< assert xmlbody /user/username=testuser1
< assert xmlbody /user/email_address=testuser1@test.com
> DELETE http://localhost:8080/ws/user/testuser1

Depak Vohra’s article at ONJava, shows how to perform schema validation using xerces/jaxp. Adapting his code to jython is straightforward, by adding the following imports to the test script from part 2:


from java.io import StringReader
from java.lang import System
from javax.xml.parsers import DocumentBuilderFactory
from javax.xml.parsers import DocumentBuilder
from org.xml.sax.helpers import DefaultHandler
from org.xml.sax import InputSource

System.setProperty('javax.xml.parsers.DocumentBuilderFactory',
        'org.apache.xerces.jaxp.DocumentBuilderFactoryImpl')

Depak’s Validator becomes:


class Validator(DefaultHandler):
    def __init__(self):
        self.validationError = 0
        self.saxParseException = None

    def error(self, exception):
        self.validationError = 1
        self.saxParseException = exception

    def fatalError(self, exception):
        self.validationError = 1
        self.saxParseException = exception      

    def warning(self, exception):
        pass

Finally, a new assertion method is added to the Test class:


    #
    # assert that an xml document validates against an xml schema
    #
    def assert_xmlschema(self, linearr, req, res):
        xml = res.getContent()

        factory = DocumentBuilderFactory.newInstance()
        factory.setNamespaceAware(1)
        factory.setValidating(1)
        factory.setAttribute('http://java.sun.com/xml/jaxp/properties/schemaLanguage',
                'http://www.w3.org/2001/XMLSchema')
        errhandler = Validator()
        factory.setAttribute('http://java.sun.com/xml/jaxp/properties/schemaSource',
            linearr[0])
        builder = factory.newDocumentBuilder()
        builder.setErrorHandler(errhandler)

        dom = builder.parse(InputSource(StringReader(xml)))

        if errhandler.validationError == 1:
            errmsg = '%s, %s' % (str(errhandler.validationError),
                    errhandler.saxParseException.getMessage())
        else:
            errmsg = ''

        assert errhandler.validationError != 1, errmsg

Value checking is accomplished with the following method:


    #
    # assert that a particular xml element contains a particular value
    #
    def assert_xmlbody(self, linearr, req, res):
        xml = res.getContent()
        if not self.xml or self.xml != xml:
            factory = DocumentBuilderFactory.newInstance()
            factory.setNamespaceAware(1)
            builder = factory.newDocumentBuilder()
            self.dom = builder.parse(InputSource(StringReader(xml)))
            self.xml = xml

        # get rid of the starting '/'
        # (could leave this out in the test, but it looks better in to me)
        if linearr[0].startswith('/'):
            linearr[0] = linearr[0][1:]

        # split into xml element list and a value based on the first '=' position
        equalspos = linearr[0].find('=')
        tmp = linearr[0][0:equalspos]
        value = linearr[0][equalspos+1:]
        elements = tmp.split('/')

        # loop through the elements in the list and retrieve each named node
        node = self.dom
        for x in xrange(0, len(elements)):
            nl = node.getElementsByTagName(elements[x])
            if not nl:
                raise AssertionError, 'sub element "%s" is missing' % elements[x]
            else:
                node = nl.item(0)
            if x == len(elements)-1:
                eval = node.getFirstChild().getNodeValue()
                assert eval == value, 'element %s (value "%s") does not match expected %s'
                            % (elements[x], eval, value)
                return
        raise AssertionError, 'missing element %s' % tmp

Which takes an assertion line such as “assert xmlbody /user/username=testuser1″ and looks up elements in the dom, where “user” is the root node, and “username” is a child node of user. At the moment this is very basic value checking which won’t work well for more complicated documents — but I’m trying to avoid complication as much as possible anyway, so it’s difficult to justify (to myself at least) going to greater lengths to make something more flexible. The main enhancement I’m looking to make initially is the ability to specify the nth child of a node. For example, something like the string “/list/user[2]/username” (in case it’s not painfully obvious, the second “user” element in “list”).

But for the moment, this will hopefully get me going.

TDD, Jython & REST (Part 2)

Wednesday, 28 September, 2005

In part one of this rumination, I discussed test-driven-development of a REST-style application written using Jython. An example of a test method would be something like:


def test_getvaliduser():
    req = MockHttpServletRequest('GET', 'user', 'http://localhost:8080/ws/user/testuser1', '', '')
    req.setContentType('text/html')

    res = MockHttpServletResponse()

    user.doGet(req, res)

    assert res.getStatus() == 200, 'incorrect status %s (%s)' % (res.getStatus(), res.getReason())
    assert res.getContentType().startswith('text/html'), 'expected text/html, got %s' % res.getContentType()

The main problem I have with this idea, is the amount of coding (read: effort) required for each test method, and therefore the amount of duplicated effort testing each resource (servlet). Testing other components in this manner, or testing non-standard functionality, is another matter, of course.

I’ve come up with what I believe is a more workable solution. Reducing the previous example to something like the following:


== Get Valid User
> GET http://localhost:8080/ws/user/testuser1
< assert status 200

Which is a serious reduction in the amount of typing required for a test, particularly when you add the setup functions (missing from the 'old' test example):


== Get Valid User
> PUT http://localhost:8080/ws/user '' \
    'username=testuser1&email_address=testuser1@test.com&level=1&password=password'
> GET http://localhost:8080/ws/user/testuser1
< assert status 200
< assert header Content-Type text/xml
> DELETE http://localhost:8080/ws/user/testuser1

Hopefully the script is relatively straightforward to understand: '==' signifies a new test, '>' is an http call, and 'here.

The next step is to add handlers for checking the content in the response (particularly xml), both in form and content.

(If anyone is interested in a working example, let me know and I'll endeavour to post something useable)

TDD, Jython & REST (Part 1)

Friday, 16 September, 2005

I’ve been working on a personal project for a few months now (begun while living in Thailand for a few months), combining a number of different technologies I currently find interesting. I’ve chosen Jython as the programming language in recognition of how powerful I’ve found developing in Python — the reasons for not going completely down the Python route (much as I would like to be using Py 2.4 modules) are mainly because of library issues. In particular I haven’t found a templating library as good as Velocity in the Pythonic world. Of course there is Cheetah, but while it is as close to Velocity as it’s possible to be without ’sleeping in the same bed’, there is still something about Cheetah that rubs me the wrong way. I suspect it’s simply because, as a long time Velocity user, I have become so accustomed to the techniques we use with that library, that slight changes/quirks in the other become larger issues, completely out of proportion to their actual magnitude.

REST is less a technology than a way of thinking which I’m endeavouring to apply to both personal and professional projects. How successful that application is remains to be seen, but thinking about web services in terms of a resource with a simple set of verbs, has certainly resulted in a re-think about how one approaches component development. It’s difficult to justify a full J2EE deployment (EJBs and so on) when your operations are reduced to a basic four (GET, POST, PUT, DELETE) and the business logic fits comfortably within the framework provided by a servlet (in my case a Jython-Servlet).

Finally TDD (which technically should’ve been mentioned first, considering where it falls in the development cycle), comes from the understanding that developing a project, which I hope to eventually turn into something commercially viable, requires more than just hacking together a bunch of parts in the hope that my frankenstein will live when electricity is applied to its extremities. I have to also consider the future of this system — have confidence in both my design and in any changes/refactoring I might make to it after it has a community of users.

TDD is at the crux of the code sample below. This is just the beginnings of a testing system for my rest+jython servlets.

It may make more sense, to some, to reuse what’s already available (JUnit for example, or the unit-testing modules already included in Python/Jython), but this is as much a learning exercise, as serious development, since I haven’t yet had to opportunity to apply TDD in any professional projects.

Read the rest of this entry »