Why would anyone do that?
SipUnit is a really nice SIP testing framework. Unfortunately it’s written in Java, so if you’re using it, you’re stuck with long functions, long names, long … <import info.viraptor.rants.JavaRantFactoryFactory> There’s a relatively easy way to avoid all of that by using Jython for the test cases. There are some problems to overcome first…
Running JUnit under Jython
For some reason (probably reflections failing) you cannot simply write:
def testBlah(self):
self.assertTrue(...)
and expect it to work. Creating a testcase for that function will fail with “funciton testBlah not found” or something similar in runTest(). That can be fixed fairly easily since Python / Jython are dynamic:
class JythonSipTestCase(SipTestCase):
def runTest(self):
test = getattr(self, self.getName())
if test is None:
raise Exception("test %s not available" %
(self.getName(),))
test()
Helpers…
Now that test cases can be constructed, it would be really nice to have a test suite created for each class. It should include all methods that have a name starting with “test” (alternatively, they could be decorated… whatever):
def generateTestSuite(klass): ts = TestSuite(klass.__name__) for attr in klass.__dict__: if not attr.startswith('test'): continueat = getattr(klass, attr) try: getattr(at, '__call__') except: continuets.addTest(klass(attr))return ts
What’s left now? Test classes should be automatically transformed into test suites. This can be achieved by simply importing the needed module into a variable and looking for the relevant classes:
def import_tests(name):
mod = getattr(__import__(name), name)
elements = (getattr(mod, cname) for cname in dir(mod))
tests = [x for x in elements if
type(x)==type and
x is not JythonSipTestCase and
issubclass(x, JythonSipTestCase)]
return
If you want to automatically add some asserts, you can rewrite the test files before importing them to add the typical ones where needed.
What exactly are the benefits?
Ok – all those tests could be written in either Java, or Python, it doesn’t really matter – effect is the same, but… Do you really want to care about types in your tests? Do you want to manually recompile your classes when you change any line of the test? Do you want to write 2 times as much code for java tests? Here’s a fragment of java test:
boolean ok = call_a.sendInviteOkAck();
assertTrue("sendInviteOkAck failed on `call_a`" +
call_a.format, ok);
Sure – you can put it in one line, but then every line starts with “assertSomething” and you have to look at the middle of the line to find out what the test actually does. Forget it if you want to limit the lines to 100 chars or less. Using rewriting of the python source, which was mentioned before (equivalent assert is automatically added by a short regex – more complex rewrites can be done using `rope` module)
ok = call_a.sendInviteOkAck()
Less noise, half the size and the file can be simply changed and run again without any additional steps. Testing a simple phone call takes now only 4 lines, with no explicit asserts in the source, compared to ~10 lines full of assertSomething(). There are more benefit of rewriting the source vs. using a helper function that will just do the call and then the assert. First one is that I would need N helpers for N functions in Java – here I know how to rewrite all of them, because they all behave the same way. Second is that I would need to assign some names to the objects inside the code, because the context is lost in the helper. By using rewriting I can put a part of string from code inside a fail message (for example “self.uac”) as well as the function name (yeah – it’s half of a broken lisp right here).
Comment
Commenting is closed for this article.