Testing Times for Tawny
Tawny OWL, my library for building ontologies (n.d.a) 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 (n.d.b) as well as allowing the ontology developer to choose the identifiers that they use to interact with the concepts (n.d.c) 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))
(is
(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
(is
(r/isuperclass? p/MargheritaPizza p/VegetarianPizza))
(is
(not
(o/with-probe-entities
[c (o/owlclass "probe"
:subclass p/VegetarianPizza p/CajunPizza)]
(r/coherent?)))))
----
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
jdk:
- 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.
———. n.d.b. https://www.russet.org.uk/blog/2275.
———. n.d.c. https://www.russet.org.uk/blog/2303.