1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
Title: Testing Framework
# Testing Framework
GLib provides a framework for writing and maintaining unit tests in parallel
to the code they are testing. The API is designed according to established
concepts found in the other test frameworks (JUnit, NUnit, RUnit), which in
turn is based on smalltalk unit testing concepts.
- Test case: Tests (test methods) are grouped together with their fixture
into test cases.
- Fixture: A test fixture consists of fixture data and setup and teardown
methods to establish the environment for the test functions. We use fresh
fixtures, i.e. fixtures are newly set up and torn down around each test
invocation to avoid dependencies between tests.
- Test suite: Test cases can be grouped into test suites, to allow subsets
of the available tests to be run. Test suites can be grouped into other
test suites as well.
The API is designed to handle creation and registration of test suites and
test cases implicitly. A simple call like:
```c
g_test_add_func ("/misc/assertions", test_assertions);
```
creates a test suite called "misc" with a single test case named
"assertions", which consists of running the `test_assertions` function.
In addition to the traditional `g_assert_true()`, the test framework
provides an extended set of assertions for comparisons:
`g_assert_cmpfloat()`, `g_assert_cmpfloat_with_epsilon()`,
`g_assert_cmpint()`, `g_assert_cmpuint()`, `g_assert_cmphex()`,
`g_assert_cmpstr()`, `g_assert_cmpmem()` and `g_assert_cmpvariant()`. The
advantage of these variants over plain `g_assert_true()` is that the
assertion messages can be more elaborate, and include the values of the
compared entities.
Note that `g_assert()` should **not** be used in unit tests, since it is a
no-op when compiling with `G_DISABLE_ASSERT`. Use `g_assert()` in production
code, and `g_assert_true()` in unit tests.
A full example of creating a test suite with two tests using fixtures:
```c
#include <glib.h>
#include <locale.h>
typedef struct {
MyObject *obj;
OtherObject *helper;
} MyObjectFixture;
static void
my_object_fixture_set_up (MyObjectFixture *fixture,
gconstpointer user_data)
{
fixture->obj = my_object_new ();
my_object_set_prop1 (fixture->obj, "some-value");
my_object_do_some_complex_setup (fixture->obj, user_data);
fixture->helper = other_object_new ();
}
static void
my_object_fixture_tear_down (MyObjectFixture *fixture,
gconstpointer user_data)
{
g_clear_object (&fixture->helper);
g_clear_object (&fixture->obj);
}
static void
test_my_object_test1 (MyObjectFixture *fixture,
gconstpointer user_data)
{
g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "initial-value");
}
static void
test_my_object_test2 (MyObjectFixture *fixture,
gconstpointer user_data)
{
my_object_do_some_work_using_helper (fixture->obj, fixture->helper);
g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "updated-value");
}
int
main (int argc, char *argv[])
{
setlocale (LC_ALL, "");
g_test_init (&argc, &argv, NULL);
// Define the tests.
g_test_add ("/my-object/test1", MyObjectFixture, "some-user-data",
my_object_fixture_set_up, test_my_object_test1,
my_object_fixture_tear_down);
g_test_add ("/my-object/test2", MyObjectFixture, "some-user-data",
my_object_fixture_set_up, test_my_object_test2,
my_object_fixture_tear_down);
return g_test_run ();
}
```
### Integrating GTest in your project
#### Using Meson
If you are using the Meson build system, you will typically use the provided
`test()` primitive to call the test binaries, e.g.:
```
test(
'foo',
executable('foo', 'foo.c', dependencies: deps),
env: [
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
],
protocol: 'tap',
)
test(
'bar',
executable('bar', 'bar.c', dependencies: deps),
env: [
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
],
protocol: 'tap',
)
```
#### Using Autotools
If you are using Autotools, you're strongly encouraged to use the Automake
TAP harness. You can follow the instructions in the Automake manual section [“Using the TAP test protocol”](https://www.gnu.org/software/automake/manual/automake.html#Using-the-TAP-test-protocol).
Since tests for a program using GLib are likely to be compiled executables,
they will have no file extension, and therefore you’ll want to set
`LOG_DRIVER` where the manual suggests `TEST_LOG_DRIVER` (which assumes test
programs ending in `.test`).
|