In the end I have gone with robotframework, as it is open source, well documented, and highly extensible. I've gone for the python version as opposed to jython, but this is mostly because I already have a decent python environment set up and have experience with python, but not java, so would like to be able to make use of its standard library in my test libraries. For those with a lot more experience in Java, I hear it's just as good an experience to use the jython version which gives you access to the JVM.
One thing that made my decision easier was the RIDE tool:
This is just a UI that makes it simple to put together your robot tests and manage tags and execution, that is written in wxPython. The choice of GUI framework leads to a few things being non-optimal on OSX, such as copy/paste and a few keyboard shortcuts, however this is still workable. What this tool excels at however is guiding you towards a sensible architecture. Your test suites can form a logical hierarchy, with common keywords encapsulated as a resource. The RIDE interface also make it possible to see documentation and argument hints from libraries.
For a note on libraries this is simple - all you need in order to implement a library usable from robot, is a class that sits in a file of the same name. You can then use robot's library import to initialise an instance of this class. Methods of this class are then made available by name in your robot tests.
when you then run these tests, you get an automatically generated html log/report, which reports any successes or failures, and allows you to drill down to see the finer grained results of individual test steps, or will just give you an overview of what went on:
For an example of a test library this is the skeleton of my simple class for interacting with Eggplant over XML-RPC:
class EggplantDriver(object):
#Snipped docstring and class attributes
def print_thing(self, name, value): #Snipped method
@property
def client(self): #Snipped method
def __init__(self, uri, suite, SUT=None, verbose=False): #Snipped method
def change_suite(self, new_suite): #Snipped method
def start_session(self, new_suite=None): #Snipped method
def end_session(self): #Snipped method
def connect_SUT(self, SUT=None): #Snipped method
def disconnect_SUT(self): #Snipped method
def execute(self, cmd): #Snipped method
I then subclassed this as the following:
from EggplantDriver import EggplantDriver
class SenseTalkCommands(EggplantDriver):
"""
An additional wrapper around EggplantDriver to give some common sensetalk
commands directly in Robot
"""
def Click(self, locator):
return self.execute(
"Click %s"%locator
)
def WaitFor(self, Time, Image):
return self.execute(
'WaitFor %d, %s'%(int(Time),
Image)
)
Which gives you the keywords to use as in the first screenshot - RIDE - Writing keywords.