Re: g_test with mainloop integration?



On 05/01/2008, Tim Janik <timj gtk org> wrote:
> On Fri, 4 Jan 2008, Mikkel Kamstrup Erlandsen wrote:
>
> > Hi,
> >
> > I am playing around with using the new glib testing utilities for
> > xesam-glib and I am wondering if there is any smart way to integrate
> > tests with a GMainLoop.
> >
> > The situation is that I need to test a bunch of async dbus
> > communications and for that I need a running GMainLoop. For now I have
> > a mainloop instantiated in my fixture and then start and exit the loop
> > in each test function. It seems a bit awkward to do it like this
> > because it introduces some boilerplatish code in each test case.
>
> that's what the fixture functions are for, to take over common builerplate
> parts of test functions.

Yes, that is also what I am doing. The problem is that the function
calling g_main_loop_run() does not return before that method returns.
So it have to be both started on stopped from within _one_ of setup(),
test_run(), or teardown().

> > So my question: Is there a Smart (TM) way to do this or can we add
> > something to gtestutils to make this easy peasy? I suspect that it
> > might not be that uncommon since many apps/libs revolve around a
> > GMainLoop.
>
> it's not clear to me what exactly you'd like to add to the test
> framework (since main loops can easily be created/destroyed in
> fixture functions). is there any concrete API to add you have in mind?

Let me try and make a more concrete example. In xesam-glib, to pick a
totally random project, hits a delivered async by signals, and
dbus-glib needs a mainloop to do async calls. In a perfect world my
test would look like the below pseudo code:

---------

setup (fix) {
 fix->search = create_search_on_search_engine()
}

test_run (fix) {
 Hits hits;

 start_search(fix->search);

 // below call returns control back to the main loop until the
 // signal is emitted on fix->search and then magically writes
 // the signal arg into &hits
 wait_for_signal(fix->search, "hits-added", &hits);
 assert(hits->count > 0);
}

teardown (fix) {
  clean_up (fix);
}

main () {
  add_test_with_main_loop (setup, test_run, teardown);
}

---------

The two interesting calls are wait_for_signal() and add_test_with_main_loop().

The wait_for_signal() method process the main loop until a signal is
emitted on a given object - or maybe until a timeout is reached[1].
The whole idea about that method is that it should be possible to
write your tests without using callbacks. This will help make the
tests more expressive and easily maintained.

To flag that some test case should run in a main loop you use some
special way of registering it. Like add_test_with_main_loop. There are
a lot of open questions on that one... Fx:
 - Should all three functions, setup, test_run, and teardown, be run
in the mainloop, or just test_run()
 - Should the mainloop process events in between calling the three functions?

For my purpose I think it would be nice if I could call wait_for
signal() in setup() as well, but I could live without it.

The biggest problem I see is how to pass the signal args back to the
test case. I have no idea on how to solve that.

Cheers,
Mikkel

[1]: It is up for discussion what to do if the timeout is reached.
Fail the test case? Call a callback? Let the method accept a GError
arg?... Many possibilities.


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]