When I first put together my Inkscape OpenSCAD DXF export plugin, I never considered writing unit tests for it, assuming it would be impractical. Years later, I revisited the possibility and found it to be not only practical, but absolutely necessary. A bug was reported against the plugin that only manifested in a recently released version of Inkscape which introduced a backward incompatibility.
Now, I didn’t want to go about manually testing different types of SVG elements on both current versions of Inkscape, so I set about investigating what it would take to write unit tests.
Triggering the export
Through manually toying in the Python shell, I found that I could trigger the
plugin export by instantiating the plugins effect class and calling the
affect method with an array containing the path to an SVG file as an argument.
My plugin stores the results in a member variable, so I could compare that
against known good output. Something like this:
from openscad_dxf import OpenSCADDXFEffect effect = OpenSCADDXFEffect() effect.affect(['tests/files/circle.svg']) with open('tests/files/circle.dxf', 'r') as dxf_file: self.assertEqual(effect.dxf, dxf_file.read().rstrip())
Testing multiple Inkscape versions
Testing multiple inkscape versions locally is a bit of a pain because I couldn’t find a way to have them both installed at once. Here’s where Travis came in handy. If you aren’t familiar with the Travis service, I highly recommend checking it out. With Travis I was able to specify a test matrix of multiple Python versions and multiple Inkscape versions and the service now runs my unit tests with all combinations of the specified Python and Inkscape versions. Here’s the configuration I started with:
language: python python: - "pypy" - "2.7" # Test both current major versions of Inkscape env: - INKSCAPE_VERSION="0.48.3.1-1ubuntu1.1" - INKSCAPE_VERSION="0.91.0+37~ubuntu12.04.1" # command to install dependencies install: - sudo add-apt-repository -y ppa:inkscape.dev/stable - sudo apt-get update -qq - sudo apt-get install -qq "inkscape=$INKSCAPE_VERSION" - pip install -r test-requirements.txt # command to run tests script: nosetests --with-coverage --cover-branches after_success: coveralls
Allow me to break down the important pieces here. First, we specify the Python
versions to test against. We only list
2.7 here because there is
still some Inkscape plugin code (that my plugin depends on) that doesn’t work
with Python versions greater than 3.
env section we specify the Inkscape versions to test against. The long
version strings used here are the versions of the packages in the
Inkscape.dev Ubuntu PPA.
install section, we add the PPA, install the package, and
any other Python testing packages required.
Finally, in the
script section we run the tests. I like to run my tests with
coverage, so I can run
coveralls after the tests to get a nice looking code
on the web.
With this configuration in place in my repository, all I had to do was enable the repository on travis-ci.org and push to GitHub to let Travis do it’s work.
Running Inkscape headless
In my case, I wasn’t quite finished yet. For reasons I won’t go into here, my plugin needs to spawn a full GUI instance of Inkscape to work. When running the tests locally, this is a non-issue. I just watch the windows pop in and out of existence as the tests run. However, a Travis test server is a headless environment which means it has no peripherals attached to it, including a display. When I tried to run the tests using the configuration above, they failed when trying to spawn Inkscape.
Fortunately, there is a simple way to get GUI processes to work in headless environments. There is a handy service called xvfb (X virtual framebuffer) which creates a virtual display on which to show any GUI processes. We can start the service on a Travis server with just a few extra lines of configuration:
# Start xvfb so we can run Inkscape headless before_install: - "export DISPLAY=:99.0" - "sh -e /etc/init.d/xvfb start"
With this configuration in place, all I have to do is push my changes and Travis automatically verifies that the expected dxf files get produced in both current Inkscape versions with the new code.
I hope this walkthrough of my experiences helps you to write unit tests for your own Inkscape plugin. Please feel free to browse the code to see how I fleshed out the tests from here.