Testing Python Dbus, Signals and Everything

The scene is set, you have made a wonderfully useful dbus based service in python and you’re ready to serve interesting data in a desktop agnostic and thread safe fashion with fancy asyncronous calls and lovely event signalling. But woe! you have to write some tests1 and you find quite quickly that this would require you to have a running test service and even that won’t make your tests work.

Before I move into my blog entry showing the world how I solved this really tricky problem, I want to say that I did do due diligence and did extensive searches for existing solutions, modules, examples and so on. The little I found and the mass of questions and difficulties people have had testing their dbus services in python is a tribute to how different the python testing framework is to the dbus server/client requirements.2

In a shared base module that is used by both daemon and client modules: example code

This gives you session bus, root address and service address and all will be correct in context. The client module is very simple for me, just some helper functions: example code

The daemon module is as you would expect, a bunch of dbus.service.Object classes with an extra helper: example code

Then you’ll need a few bits for the test suite, a test base module that all test cases inherit example, a daemon service script which is run when tests are run example and finally a test suite with some tests example3.

As you can see you need a running service with a test address and a way to start and stop that service if it’s not already running. You also need to manage the gobject loops for testing signals from your dbus service and this is done using the much loved python threading module.

I hope these examples will prove useful to others.

1 Or had a requirement to write them prior to writing any code, depending on your method.
2 Do post a comment below if you know of other people’s examples and successes.
3 I’ve hacked this together from my project code to give example, it may not run.