Testing Times for Tawny


Tawny OWL, my library for building ontologies [@url:www.russet.org.uk/blog/2254] is now reaching a nice stage of maturity; it is possible to build ontologies, reason over them and so forth. We have already started to use the programmable nature of Tawny, trivially with disjoints [@url:www.russet.org.uk/blog/2275] as well as allowing the ontology developer to choose the identifiers that they use to interact with the concepts [@url:www.russet.org.uk/blog/2303] However, I wanted to explore further the usefulness of a programmatic environment.

One standard facility present in most languages is a test harness, and Clojure is no exception in this regard. Tawny already comes with a set of predicates for testing superclasses, both asserting and inferred, which provides a good basis for unit testing. So, this example using my test Pizza ontology shows a nice example, essentially testing definitions for CheesyPizza --- these should in both a positive and negative definition.

(deftest CheesyShort
  (is (r/isuperclass? p/FourCheesePizza p/CheesyPizza))
  (is (r/isuperclass? p/MargheritaPizza p/CheesyPizza))
   (not (r/isuperclass? p/MargheritaPizza p/FourCheesePizza))))

While ths is nice, it is not enough in some cases where I wanted to test that things that do not happen. For this I introduce a new macro, with-probe-entities which adds "probe classes" into the ontology --- that is a class which is there only for the purpose of a test. In this case, I test the definition of VegetarianPizza to see whether MargheritaPizza reasons correctly as a subclass. Additionally, though, I also check to see whether a subclass of VegetarianPizza and CajunPizza --- which contains sausage --- is inconsistent. This test could be more specific, as it tests for general coherency, although I do check for this independently. The with-probe-entities macro cleans up after itself. All entities (which can be of any kind and not just classes) are removed from the ontology afterwards; so independence of testing is not compromised).

(deftest VegetarianPizza
   (r/isuperclass? p/MargheritaPizza p/VegetarianPizza))

      [c (o/owlclass "probe"
                     :subclass p/VegetarianPizza p/CajunPizza)]

Of course, a natural consequence of the addition of tests is the desire to run
them frequenty; more over, the desire to run them in a clean environment. The
solution to this turns out to be simple. https://travis-ci.org/[Travis-CI]
integrates nicely with github -- so the addition of a simple YAML file of this
form enables a Continuous Integration, of both the Pizza ontology and the
environment (such as Tawny, for instance).

language: clojure
lein: lein2
  - openjdk7

The output of this process is
https://travis-ci.org/phillord/tawny-pizza[available] for all to read, along
with the tests for my mavenized version of
https://travis-ci.org/phillord/hermit-maven[Hermit], and also
https://travis-ci.org/phillord/tawny-owl[tawny] itself. This is not the first
time that ontologies have been continuously integrated
kurl:bio-ontologies.knowledgeblog.org/405[]; however, the nice advantage of
this is that I have not had to install anything. It even works against
external ontologies: so we have both
https://travis-ci.org/phillord/tawny-go[GO] and
https://travis-ci.org/phillord/tawny-obi[OBI]. Currently, these work against
static versions of GO and OBI. I could automate this process from the
respective repositories of these projects, by pulling with git-svn and pushing
again to github.

All in all, though, the process of recasting ontology building as a
programming task is turning out to be an interesting experience. Much of the
tooling that enables collaborative ontology building just works. It holds much
promise for the future.