mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-25 15:06:14 +01:00
parent
d8b25ecda3
commit
1a090564d2
@ -49,6 +49,7 @@ content_files = [
|
||||
"logging.md",
|
||||
"main-loop.md",
|
||||
"reference-counting.md",
|
||||
"testing.md",
|
||||
"threads.md",
|
||||
]
|
||||
content_images = [
|
||||
|
@ -158,6 +158,7 @@ expand_content_files = [
|
||||
'logging.md',
|
||||
'main-loop.md',
|
||||
'reference-counting.md',
|
||||
'testing.md',
|
||||
'threads.md',
|
||||
]
|
||||
|
||||
|
183
docs/reference/glib/testing.md
Normal file
183
docs/reference/glib/testing.md
Normal file
@ -0,0 +1,183 @@
|
||||
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; GLib provides template files for easily integrating with it:
|
||||
|
||||
- [`glib-tap.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk)
|
||||
- [`tap-test`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test)
|
||||
- [`tap-driver.sh`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh)
|
||||
|
||||
You can copy these files in your own project's root directory, and then set
|
||||
up your `Makefile.am` file to reference them, for instance:
|
||||
|
||||
```
|
||||
include $(top_srcdir)/glib-tap.mk
|
||||
|
||||
# test binaries
|
||||
test_programs = \
|
||||
foo \
|
||||
bar
|
||||
|
||||
# data distributed in the tarball
|
||||
dist_test_data = \
|
||||
foo.data.txt \
|
||||
bar.data.txt
|
||||
|
||||
# data not distributed in the tarball
|
||||
test_data = \
|
||||
blah.data.txt
|
||||
```
|
||||
|
||||
Make sure to distribute the TAP files, using something like the following in
|
||||
your top-level `Makefile.am`:
|
||||
|
||||
```
|
||||
EXTRA_DIST += \
|
||||
tap-driver.sh \
|
||||
tap-test
|
||||
```
|
||||
|
||||
`glib-tap.mk` will be distributed implicitly due to being included in a
|
||||
`Makefile.am`. All three files should be added to version control.
|
||||
|
||||
If you don't have access to the Autotools TAP harness, you can use the
|
||||
gtester and gtester-report tools, and use the
|
||||
[`glib.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk)
|
||||
Automake template provided by GLib. Note, however, that since GLib 2.62,
|
||||
gtester and gtester-report have been deprecated in favour of using TAP. The
|
||||
`--tap` argument to tests is enabled by default as of GLib 2.62.
|
@ -67,193 +67,6 @@
|
||||
* See https://gitlab.gnome.org/GNOME/glib/-/issues/2885 */
|
||||
#define TAP_SUBTEST_PREFIX "# " /* a 4-space indented line */
|
||||
|
||||
/**
|
||||
* SECTION:testing
|
||||
* @title: Testing
|
||||
* @short_description: a test 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
|
||||
* |[<!-- language="C" -->
|
||||
* g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* g_test_init() should be called before calling any other test functions.
|
||||
*
|
||||
* 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:
|
||||
* |[<!-- language="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
|
||||
*
|
||||
* If you are using the [Meson](http://mesonbuild.com) build system, you will
|
||||
* typically use the provided `test()` primitive to call the test binaries,
|
||||
* e.g.:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* 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()),
|
||||
* ],
|
||||
* )
|
||||
*
|
||||
* 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()),
|
||||
* ],
|
||||
* )
|
||||
* ]|
|
||||
*
|
||||
* If you are using Autotools, you're strongly encouraged to use the Automake
|
||||
* [TAP](https://testanything.org/) harness; GLib provides template files for
|
||||
* easily integrating with it:
|
||||
*
|
||||
* - [glib-tap.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk)
|
||||
* - [tap-test](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test)
|
||||
* - [tap-driver.sh](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh)
|
||||
*
|
||||
* You can copy these files in your own project's root directory, and then
|
||||
* set up your `Makefile.am` file to reference them, for instance:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* include $(top_srcdir)/glib-tap.mk
|
||||
*
|
||||
* # test binaries
|
||||
* test_programs = \
|
||||
* foo \
|
||||
* bar
|
||||
*
|
||||
* # data distributed in the tarball
|
||||
* dist_test_data = \
|
||||
* foo.data.txt \
|
||||
* bar.data.txt
|
||||
*
|
||||
* # data not distributed in the tarball
|
||||
* test_data = \
|
||||
* blah.data.txt
|
||||
* ]|
|
||||
*
|
||||
* Make sure to distribute the TAP files, using something like the following
|
||||
* in your top-level `Makefile.am`:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* EXTRA_DIST += \
|
||||
* tap-driver.sh \
|
||||
* tap-test
|
||||
* ]|
|
||||
*
|
||||
* `glib-tap.mk` will be distributed implicitly due to being included in a
|
||||
* `Makefile.am`. All three files should be added to version control.
|
||||
*
|
||||
* If you don't have access to the Autotools TAP harness, you can use the
|
||||
* [gtester][gtester] and [gtester-report][gtester-report] tools, and use
|
||||
* the [glib.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk)
|
||||
* Automake template provided by GLib. Note, however, that since GLib 2.62,
|
||||
* [gtester][gtester] and [gtester-report][gtester-report] have been deprecated
|
||||
* in favour of using TAP. The `--tap` argument to tests is enabled by default
|
||||
* as of GLib 2.62.
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_test_initialized:
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user