I like to write unit tests for my code and I also like to know whether my unit tests are actually testing my code. In Java I would use Maven and Cobertura to measure how
much of my code is actually exercised, and when I bend my mind around Haskell I use HPC.
I have been experimenting with Clojure and it has a nice testing library but the only way I have found to measure coverage is to use Cobertura and squint at the generated class names to work out what I haven’t covered. So I have started on the road to creating a coverage tool for Clojure written in Clojure. This blog entry contains my initial steps and design sketches towards creating the tool.
Ideally I’d like to measure my coverage like this:
That isn’t functional code yet and may not be what I finally produce, it might not even be valid Clojure since I haven’t even bashed it into a REPL yet.
As Clojure is a Lisp, and we are testing our own code – i.e. we have the source code – we should be able to measure the coverage using Clojure. This can achieved by rebinding the functions under test with instrumented functions;
this is what I envisage the cover function is doing:
Which can be achieved using a binding function:
So assuming I can write the cover function I will need to instrument a function. Let’s start simply and ignore the complicated stuff such as conditional statements and multiple bodies until later. If we have this simple function
I would like an instrumented version to wrap each s-expression with a function that records that the s-expression has been called, for now we will just print a message.
Testing that in the REPL seems to reveal that I am moving in the right direction:
To convert the first function to the instrumented function I need a couple of auxiliary functions and a macro:
If you know some Clojure that code demonstrates some of the problems I haven’t solved yet when measuring coverage, for example the :else clause will need to be covered as well as functions in binding statements. Testing that code in the REPL gives us a reasonable result:
So if I now replace the record function with something else I may be able to generate some coverage for a function. I am going to use a map held by a ref to store the coverage information, a function to register a particular
s-expression with the ref and a function to increment the count.
Lets test that:
If I modify our wrapping functions I can create the coverage records ready to be incremented.
Testing that code:
And that is as far as I have got. I need to change my record function to increment the coverage records, make my wrap function cope with conditionals and other complexities and write my rebinding function. Hopefully next month I will have moved it along a little bit further.
SpringSource, a division of VMware, Inc. today announced the acquisition by VMware of Rabbit Technologies, Ltd, a company set up by LShift and partners Monadic and CohesiveFT.
SpringSource, a division of VMware, Inc. today announced the acquisition by VMware of Rabbit Technologies, Ltd.
Rabbit Technologies is an open source software company based in the United Kingdom. SpringSource will add the RabbitMQ open messaging system into its suite of technologies that reduce the complexity associated with development, deployment and management of enterprise applications.
LShift has been involved in the development of RabbitMQ from building the first prototypes and then providing the subsequent engineering and development backbone to the project. LShift founded Rabbit Technologies Ltd alongside our partners at Monadic and CohesiveFT.
LShift EO, Mike Rowlands, said “We are intensely proud of our contribution to making RabbitMQ the market leading AMQP solution, and we welcome SpringSource’s acquisition of Rabbit Technologies as a confirmation of the quality of the software we have produced and in terms of its ongoing potential, as it will see the resources of VMWare committed to its further success.”
When I’m doing development on an existing software project, and especially when I’m trying to bugfix something with a Debian package,Â I find that I install random packages I need to rebuild something, and then later on I’m wondering why I’ve got those installed. I tend to try to keep with the philosophy that the bits of software I’m using are prettyÂ knowledgeableÂ about whatever they’re intended to do, and so trusting them to make smart decisions is a good idea. For package managers, this means I should only keep track of the software that I actually use, and tell the package manager that everything else has been automatically installed and can therefore be removed when they cease to be a dependency of something I actually need. Having packages that I only installed for building something else without a record of that in the package management system breaks that mental model.
Enter dh-builddep-metapackage (the naming is inline with the names used by the debhelper scripts used for other debian packaging stuff). dh-builddep-metapackage builds build-dependency metapackages in order to ease package
management for package rebuilders. In effect, it builds a “<packageÂ name>-builddep” package that has no content, but depends on everything that theÂ existing package build-depends on.Â By using dh-builddep-metapackage to create metapackages rather than using “apt-get build-dep”, I keep a record in the package management about why I need a particular development package, and can remove the dependant packages when I’m no longer working with the relevant source package.
I think someone’s done this before, but some work with Google didn’t find it, and it was an interesting exercise anyway. Standard usage is “dh-builddep-metapackage -b <package name>”, which will create the metapackage data and build the package for you using dpkg-buildpackage. A folder called “<package name>-<package version>” will be created in the current local directory, and if an existing folder exists then dh-builddep-metapackage will refuse to overwrite it (unless you give the -o/–overwrite option).
So far I’ve used it a few times, and it’s quite nice to have those packages around to remind me about the dependencies. I’m considering building a full repository with *-builddep packages for everything in the Debian archives, but I’d like to make sure I’d use this enough first.
You are currently browsing the LShift Ltd. blog archives for April, 2010.