8.3. Unit Testing ​
Vala programs use the same unit-test harness as GLib and GTK: the GLib.Test API. Tests are ordinary Vala functions registered with the harness; when you run the compiled binary, GLib prints TAP-style output and sets the process exit code so CI systems (and meson test) can tell pass from fail.
For a Unit Testing Sample Code see: Testing Samples.
Minimal harness ​
Every test executable should call Test.init before registering tests, then Test.run after registration:
void add_tests () {
Test.add_func ("/example/math/adds", () => {
assert (1 + 1 == 2);
});
}
void main (string[] args) {
Test.init (ref args);
add_tests ();
Test.run ();
}Compile and run:
valac --pkg glib-2.0 tests.vala
./testsTest.add_func takes a hierarchy path (by convention starting with /) and a callback. Paths group related cases in the TAP log and in tools that understand GLib’s test tree.
Assertions and messages ​
Plain assert (condition) is the usual choice in Vala tests. When you need a custom failure explanation, record context with Test.message and stop the case with Test.fail, or skip unsupported platforms with Test.skip:
Test.add_func ("/example/strings/concat", () => {
string got = "foo" + "bar";
if (got != "foobar") {
Test.message ("expected foobar, got %s", got);
Test.fail ();
}
});The C GLib headers also expose g_assert_cmpstr-style macros for richer logs; those are not always wrapped in Vala’s glib-2.0 vapi, so many projects stick to assert or explicit Test.message blocks.
Suites and shared setup ​
For several cases that share expensive setup, register a TestSuite or split setup into helpers called from each Test.add_func callback. GLib also provides Test.add_data_func / Test.add_data_func_full for table-driven cases where the same function runs with different user data (see the GLib documentation for the exact C→Vala naming you need in your Vala version).
Subprocess and timing helpers ​
GLib can re-run the test binary in a subprocess to isolate crashes or to test MainLoop-driven code. See the subprocess and trap-related symbols on GLib.Test (for example Test.trap_subprocess) when a unit must simulate a separate process or capture fatal errors.
Meson and CI ​
Meson’s test() target runs an executable and interprets its exit status. A minimal meson.build is shown on the Testing Samples page. In CI, run meson test -C build (or your build directory) so every registered Test.add_func is executed automatically.
See also ​
- Testing Samples — full copy-paste example and Meson snippet
- GLib.Test reference
- 8.1. Debugging — using debuggers when a test or app crashes
