Skip to content

Added content on writing unit tests and mocks in C with AUM #350

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions tech/languages/c/unit_tests_and_mocks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
title: Unit Tests and Mocks
subsection: c
order: 5
---

# Unit tests

Unit tests are an efficient way to improve software quality. They are especially well suited if you want to avoid code regressions due to code modifications.

A unit test is a snipet of code which exercises only a small portion of the whole software. It is usually made of three parts:
* prepare the inputs,
* call the function under test,
* check that something went well.

Each unit test can be viewed as a small constraint on the possible behaviours of the software. Run together several small unit tests can greatly increase your confidence in the code base. A test is also a form of executable documentation: if you break a test you can read its name and scenario to understand the intent of the code that was just modified.

AUM is a library that lets you easily write and execute unit tests in C. The latest releases, installation instructions and documentation are available [here](https://github.com/airbus-cyber/aum).
Here is an example that gives you a concrete exemple of AUM in action:

```c
AUM_TEST(malloc__should_return_a_non_null_pointer)
{
char *result = malloc(10 * sizeof(char));
AUM_ASSERT_PTR_NOT_NULL(result);
free(result);
}
```

This test checks that calling function `malloc` returns a non-null pointer.

# Mocks

Sometimes, when writing tests, it is necessary to control the behavior of a function. It could be that the function can not be run automatically; for instance in the case of user interactions or network accesses. Or that you want to exercise corner cases; for instance when the program runs out of memory, or when file accesses fail. In these cases, you use function mocks.

Here is a test with a mock of `malloc` written with AUM:

```c
AUM_MOCK_CREATE(void *, malloc, size_t);

AUM_TEST(aum_mock_will_return__should_set_return_code)
{
aum_mock_will_return("malloc", 0);

char *result = malloc(10 * sizeof(char));
AUM_ASSERT_PTR_NULL(result);
}
```

In this example, function `malloc` is replaced by a mock which is supposed to always return `NULL`.

# Some best practices

Here are some best practices related to unit tests:
* If you don't want to spend too much time on writing tests, a cost-effective approach consists in introducing at least one new test for each bug that is detected and fixed.
* Better, you can follow Test Driven Development (TDD): it roughly consists in writing each test before the corresponding code. If your project is starting from scratch, then you are in the ideal situation for TDD: you will be able to achieve 100% code coverage at a relatively low cost.
* At least, it is always profitable to set up a continuous integration server to build, analyse and test your code. In doing so, you know at all times whether everything still works or not.