AceUnitAceUnit Manual

Table of Contents

Introduction

AceUnit (Advanced C and Embedded Unit): a comfortable C code unit test framework. AceUnit is JUnit 4.x style, easy, modular and flexible. AceUnit can be used in resource constraint environments, e.g. embedded software development.

What's AceUnit for you?

AceUnit is a unit test framework.

As such it provides a framework for you that you can use for writing your unit tests. As a framework for unit testing, AceUnit provides you with a hierarchical test structure. Test Suites consist of Test Suites (recursively) and Test Fixtures. A Test Fixture consists of Test Cases that can have a preparation (beforeClass / before) and cleanup (afterClass / after). AceUnit provides a Runner that will automatically traverse that hierarchical structure, run all the tests from it and log the results. AceUnit also provides a Generator that will derive the structural information required by the Runner from some simple conventions. The Generator replaces what in other languages (like Java) is provided by reflection. The Runner also includes an assertion and a logging infrastructure.

The most frequent use of AceUnit is to link AceUnit and tests written for AceUnit with the testling that you want to test with AceUnit. Because usually the testling already has a main() and because (unlike e.g. in Java) the testling can have only one main(), AceUnit does not, unlike e.g. JUnit, provide its own main(). To run AceUnit, hook the invocation of the Runner in your program wherever it looks appropriate to you. An example would be somewhere within or near main(), where the arguments are parsed.

Quick Overview

Unit Tests in AceUnit are declared using annotations. This works pretty much the same as JUnit 4.x. JUnit 4.x can be considered industry reference for unit test frameworks. Much of AceUnit was modelled after JUnit 4.x.

The most important annotation that you will need is A_Test. The A_Test annotation tells AceUnit that a function is a unit test. Simply place this as a modifier before your function declaration, where you would write static in case you would declare your function static. This annotation will be the main interface between your unit tests and the AceUnit framework which will run them.

Example

A_Test void someTestMethod() {
    // test case implementation for this test case goes here
}

Assume your source is named MyTest.c. There are only two more things which you will need in your source. Both of these things are very easy.

That's all what you need.

What is AceUnit.jar?

AceUnit.jar is a Java program and the core for automation in AceUnit. It scans a test source code and will generate all required information that the AceUnit framework will need to run your tests. That information will be placed in the specified header file.

We know that running Java in a C environment is not convenient. As soon as the main framework is stable, there will be a C implementation of AceUnit.jar.

Variants of Unit Test Declaration

AceUnit supports the following styles of declaring unit tests:

Annotation based testing

When declaring tests with annotations, the following annotations are available:

A_Test
Test annotation, use for test cases.
A_Before
Before annotation, use for methods that should be invoked before each test case in a fixture.
A_After
After annotation, use for methods that should be invoked after each test case in a fixture.
A_BeforeClass
BeforeClass annotation, use for methods that should be invoked once for the fixture before all of its test cases.
A_AfterClass
AfterClass annotation, use for methods that should be invoked once for the fixture after all of its test cases.
A_Ignore
Ignore annotation, use for test cases to ignore. This annotation is only allowed for methods annotated as A_Test.

Naming Convention based testing

The following naming convention is recommended for the test names:

test*
A test case method.
before*
Before method, should be invoked before each test case in a fixture. Note: "*" MUST not match "Class*".
after*
After method, should be invoked after each test case in a fixture. Note: "*" MUST not match "Class*".
beforeClass*
BeforeClass method, should be invoked once for the fixture before all of its test cases.
afterClass*
AfterClass method, should be invoked once for the fixture after all of its test cases.

AceUnit Glossary

Annotation
A C preprocessor macro that is defined empty for the compiler but meaningful for the AceUnit test code generator.
Class
See Fixture.
Fixture
A fixture, aka Test Class, is a collection of tests along with operations that shall be performed before or after all or each of the tests contained in the fixture.
Test
A single test case is a simple C function that will be called to perform the test.
Test Case
See Test.
Test Class
See Fixture.
Test Fixture
See Fixture.

The scheme of writing AceUnit tests

Writing AceUnit tests is easy, very easy.

Writing your first AceUnit test first software.

Our scenario is developing a sorting algorithm. A sorting algorithm works if the list that it was sorting is sorted after the algorithm is done. To verify whether a sorting algorithm works, we need verify that its data was sorted. Both, the sorting and the verification need a comparator that determines whether an element should be sorted before or after another element.

Testing Comparator

The comparator works when it returns the expected result for each pair of values.

/** A Comparator compares two values and returns a comparison result.
 * @param o1 Pointer to first object to compare.
 * @param o2 Pointer to second object to compare.
 * @return Comparison result
 * @retval 0 if o1 and o2 are equal.
 * @retval <0 if o1 should be sorted before o2.
 * @retval >0 if o1 should be sorted after o2.
 */
typedef int8_least_t(*comparator)(const void *o1, const void *o2);

For testing purposes, we want to sort ints. So the first thing that we do is we test whether our comparator implementation works.

/** Comparator for int values.
 * @see comparator
 */
int8_least_t compareInt(const void *o1, const void *o2) {
    return 0;
}

It is obvious that our current implementation is bogus. In test first programming, you intentionally start with a bogus implementation to verify that your test actually detects that the implementation is bogus.

/** Tests that #compareInt() works. */
A_Test void testCompareInt() {
    int n1;
    int n2;

    n1 = 0;
    n2 = 0;
    assertEquals("Comparing two equal numbers must return 0.", 0, compareInt(&0, &1));

    n1 = 1;
    n2 = 2;
    assertTrue("Comparing 1 with 2 must return a value <0.", compareInt(&n1, &n2) < 0);

    n1 = 2;
    n2 = 1;
    assertTrue("Comparing 2 with 1 must return a value >0.", compareInt(&n1, &n2) > 0);
}

Options

AceUnit supports the following options:

#define ACEUNIT_STATIC_ASSERTIONS
By defining this macro you will cause annotations to be equivalent to static. That way you have easy and flexible control over whether test methods are static or not.

Declaring test methods as static has a significant advantage. You will be able to use the same name in different fixtures and still build and run them all together. For logging, it is not required that test methods have unique names. Logging will always also include the associated fixture (e.g. filename + line number). So you will always uniquely identify which test case failed, even if the names of the test cases are not unique.

However, there are debuggers which will cause head ache if you try to debug functions which are static. Some tool chains (compilers / linkers) will not emit proper debug information for functions which are static.

The pros and cons for static test methods are both very significant. Whether or not you want to use static depends on your environment. Because of that, we've left the choice to you.

But we've prepared everything for you. Toggling between these two options is as simple as (not) defining this macro.
#define ACEUNIT_EMBEDDED
By defining this macro you will turn AceUnit into embedded mode. In embedded mode, AceUnit tries to consume as little memory as possible. For instance, all strings are replaced by 16 bit values. Note: Currently this macro is not 100% functional.
Feedback: webmaster
$Id: manual.xhtml 533 2009-08-21 19:53:15Z christianhujer $
Copyright © 2007 - 2011 The AceUnit Developers. All Rights Reserved.