**µTest — A small C testing library** ## What is µTest? µTest aims to be a small unit testing library for C projects, with an API heavily modelled on high level [Behavior-Driven Development][bdd] frameworks like [Jasmine][jasmine] or [Mocha][mocha]. [bdd]: https://en.wikipedia.org/wiki/Behavior-driven_development [jasmine]: https://jasmine.github.io/ [mocha]: https://mochajs.org/ ## Adding µTest to your project The preferred way to use µTest is to include it in your own projects using a Git sub-module, and then building µTest as a static library. If you are using [Meson](http://mesonbuild.com), you can use a wrap file in the `subprojects` directory: ``` [wrap-git] directory=mutest url=https://github.com/ebassi/mutest.git revision=master ``` and then use the `fallback` dependency type: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ mutest_dep = dependency('mutest-1', fallback: [ 'mutest', 'mutest_dep' ], default_options: ['static=true'], required: false, disabler: true, ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ !!! Note The `static` option will build µTest as an uninstalled static library. You can remove the `default_options` argument to get an installed shared library. µTest can also build a shared library and a [pkg-config](https://www.freedesktop.org/wiki/Software/pkg-config/) file to describe the necessary compiler and linker flags, if you want to install µTest in your library path; if you decide to depend on the shared library, you can use the normal `pkg-config`-based dependency discovery. For instance, if you are using [Meson](http://mesonbuild.com): ```meson mutest_dep = dependency('mutest-1') ``` And if you're using Autotools: ```m4 PKG_CHECK_MODULES(MUTEST, [mutest-1]) AC_SUBST(MUTEST_CFLAGS) AC_SUBST(MUTEST_LIBS) ``` ## Writing tests using µTest Writing a test program using µTest requires initializing the test framework, defining the various tests, and gathering the results. For convenience, µTest provides a simple macro meant to replace the `main` entry point of any C binary: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MUTEST_MAIN ( // your code goes here ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The `MUTEST_MAIN` macro will initialize µTest and print the report. Each µTest-based test starts from a *suite*, which is created by calling `mutest_describe()` in the main entry point of your test binary: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ MUTEST_MAIN ( mutest_describe ("A test suite", main_suite); ) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A test binary can have multiple suites. The purpose of the `main_suite()` function is to create a *specification*, or *spec*. A spec describes an aspect of your data type, service, or API. Each spec is made of various expectations, which are defined by calling `mutest_it()`: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void main_suite (void) { mutest_it ("is made of at least one spec", first_spec); mutest_it ("can contain multiple specs", second_spec); mutest_it ("can have specs that can be skipped", skipped_spec); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As you can see, the description of suites and specs tries to match a natural language description of what the suite is about, and what aspect of the API is covered by each spec. The descriptions will be logged in the test output. Inside each spec we have *expectations* that must be satisfied, in order to say that the test suite is successful. An expectation is made of three parts: - a description of the expectation - the value we are testing - a *matcher function*, which will compare the value we are testing with the expected value ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void first_spec (void) { bool a = true; mutest_expect ("a to be true", mutest_bool_value (a), mutest_to_be, true, NULL); mutest_expect ("a not to be false", mutest_bool_value (a), mutest_not, mutest_to_be, false, NULL); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Expectations can chain multiple matching functions in order to create multiple conditions that must be all satisfied: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void second_spec (void) { // The get_greeting() function is defined elsewhere, and // we are testing its output const char *str = get_greeting (); mutest_expect ("get_greeting() to return all parts of a greeting", mutest_string_value (str), mutest_to_start_with_string, "hello", mutest_to_contain, ",", mutest_to_end_with_string, "world", NULL); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the example above, the expectation will only be satisfied if all three matchers are successful. Expectations can be programmatically skipped. For instance, if you haven't implemented some functionality, yet. These expectations will be satisfied, but still logged not as successes: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ static void skipped_spec (void) { // The get_answer() function is defined elsewhere int answer = get_answer (); mutest_expect ("an answer to the ultimate question of life, the universe, and everything", mutest_int_value (answer), mutest_skip, "Deep Thought hasn't finished yet", NULL); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In the example above, the `skipped_spec()` specification will succeed, but it will be marked as skipped. ## Output formats By default, µTest uses an output similar to Mocha: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $ ./test-suite A test suite is made of at least one spec ✓ a to be true ✓ a not to be false 2 passing (80.0 µs) can contain multiple specs ✓ get_greeting() to return all parts of a greeting 1 passing (60.0 µs) can have specs that can be skipped - an answer to the ultimate question of life, the universe and everything 0 passing (34.0 µs) 1 skipped Total 3 passing (202.0 µs) 1 skipped ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Additionally, µTest supports [TAP](https://testanything.org/)—Test Anything Protocol. If you have a TAP harness, like [prove(1)](https://linux.die.net/man/1/prove), you can use the `MUTEST_OUTPUT` environment variable set to `tap` in order to get a TAP output: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ $ MUTEST_OUTPUT=tap ./test-suite # A test suite # is made of at least one spec ok 1 - a to be true ok 2 - a not to be false # can contain multiple specs ok 3 - get_greeting() to return all parts of a greeting # can have specs that can be skipped ok 4 - an answer to the ultimate question of life, the universe and everything # SKIP: Deep Thought hasn't finished yet 1..4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## API Reference - [General](./mutest-general.md.html) - [Matchers](./mutest-matchers.md.html) - [Value wrappers](./mutest-wrappers.md.html) - [Hooks](./mutest-hooks.md.html) ## Copyright and license Copyright 2019 Emmanuele Bassi µTest and this documentation are released under the terms of the [MIT](https://opensource.org/licenses/MIT) license. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.