Is there a way to unit test Gtk/GLib code written in Python?
Asked Answered
M

1

6

I'm in the process of writing a small/medium sized GUI application with PyGObject (the new introspection based bindings for Gtk). I started out with a reasonable test suite based on nose that was able to test most of the functions of my app by simply importing the modules and calling various functions and checking the results.

However, recently I've begun to take advantage of some Gtk features like GLib.timeout_add_seconds which is a fairly simple callback mechanism that simply calls the specified callback after a timer expires. The problem I'm naturally facing now is that my code seems to work when I use the app, but the testsuite is poorly encapsulated so when one test checks that it's starting with clean state, it finds that it's state has been trampled all over by a callback that was registered by a different test. Specifically, the test successfully checks that no files are loaded, then it loads some files, then checks that the files haven't been modified since loading, and the test fails!

It took me a while to figure out what was going on, but essentially one test would modify some files (which initiates a timer) then close them without saving, then another test would reopen the unmodified files and find that they're modified, because the callback altered the files after the timer was up.

I've read about Python's reload() builtin for reloading modules in the hopes that I could make it unload and reload my app to get a fresh start, but it just doesn't seem to be working.

I'm afraid that I might have to resort to launching the app as a subprocess, tinkering with it, then ending the subprocess and relaunching it when I need to guarantee fresh state. Are there any test frameworks out there that would make this easy, particularly for pygobject code?

Maudiemaudlin answered 11/6, 2012 at 8:8 Comment(1)
How did this go in the end - subprocess doesn't seem like the worst way of going here ?Moldy
M
2

Would a mocking framework help you isolate the callbacks? That way, you should be able to get back to the same state as when you started. Note that a SetUp() and tearDown() pattern may help you there as well -- but I am kind of assuming that you already are using that.

Mawkin answered 11/6, 2012 at 8:12 Comment(3)
I don't think mocking is quite what I'm looking for. I have a small dataset that I use for testing and replacing it with mocks wouldn't really fix the problem I'm having, which is that the actual program logic code uses time-delay callbacks which behave poorly in a rapidly-executing test environment. I am using setup/teardown funcs, but I have not been able to write a successful teardown that can actually unload the program from memory and then reload it in a fresh state. There's always lingering callbacks that interfere from one test to the next.Maudiemaudlin
I was thinking of mocking the callbacks but that may or may not be suitable for your needs.Mawkin
What I've done now that seems to be working is to just manually call the callback from the test, and then be a little bit more aggressive about clearing the callbacks with GLib.source_remove, and it seems to be working. Thanks though.Maudiemaudlin

© 2022 - 2024 — McMap. All rights reserved.