Ada: AUnit

This article describes how to use

  • AUnit, a unit test framework for Ada, and

  • GNATtest, a tool for creating test scaffolds.

An overview of AUnit can be found in the AUnit cookbook. GNATtest is described in the GNATtest user guide.

Installation

AUnit

Check out the GitHub repository and compile.

git clone https://github.com/AdaCore/aunit.git
cd aunit
make

Next, install.

make install

Note

On some systems gprbuild needs to be called with an -aP flag: gprbuild -aP /usr/share/gpr. Alternatively, if you use an Ailre-based workflow, you might use the Alire installation as the root directory: make install INSTALL=~/.alire.

GNATtest

alr install gnattest

Assertions

Assert

To use the following examples outside a test harness generated with GNATtest you need to add with "aunit"; to your project’s .gpr file.

with "aunit";

project Hello is
  for Languages use ("Ada");
  for Source_Dirs use ("src");
  for Object_Dir use "build";

  for Main use ("main.adb");

  package Compiler is
    for Switches ("Ada") use ("-g", "-gnat2022", "-gnatw.e", "-gnatw.Y", "-gnatw.N");
  end Compiler;
end Hello;

At the lowest level, a unit test consists of assertions. To this end, AUnit provides the procedure AUnit.Assertions.Assert.

-- src/main.adb

with AUnit.Assertions; use AUnit.Assertions;

procedure Main is
begin
  Assert (
    True,                   -- Expected : Boolean
    "should not be false"); -- Message  : String
end Main;

Assert_Exception

To ensure that an exception is raised, we use the procedure Assert_Exception.

-- src/lib.ads

package Lib is

  My_Exception : exception;

  procedure Proc;

end Lib;
-- src/lib.adb

package body Lib is

  procedure Proc is
  begin
    raise My_Exception with "This has gone very wrong.";
  end Proc;

end Lib;

Next we alter our main.adb source file like so:

-- src/main.adb

with AUnit.Assertions; use AUnit.Assertions;
with Lib;              use Lib;

procedure Main is
begin
  Assert_Exception (
    Proc'Access,              -- Procedure
    "should raise exception", -- Message   : String
    "lib.adb",                -- Source    : String  (optional)
    5);                       -- Line      : Natural (optional)
end Main;

Test Fixture

The central concept in AUnit is a test fixture. We create a test fixture by extending the class AUnit.Test_Fixtures.Test_Fixture.

This class allows us to overwrite two base operation procedures:

  • Set_Up

  • Tear_Down

We use both to alter the state of the test fixture object. In addition, a test fixture can have more base operation procedures each implementing a test.

GNATtest

Instead of setting up a test fixture by hand, we use the tool GNATtest to create a test scaffold. Part of that scaffold is a test harness that allows us to run the tests.

We create the scaffold assuming the project is described in hello.gpr.

gnattest -Phello --subdirs=tests

This creates a directory for the test scaffold in ./src/tests and a directory for the test harness in ./build/gnattest/harness.

We build the test harness using the generated Makefile. This creates an executable test_runner.

cd build/gnattest/harness
make
./test_runner

GNU Make Workflow

-- Makefile

PROJECT := hello
HARNESS := build/gnattest/harness

.PHONY: all
all:
       gprbuild -P$(PROJECT)

.PHONY: clean
clean:
       $(RM) -r build
       $(RM) -r lib

.PHONY: test
test: $(HARNESS)
       (cd $^ && make && ./test_runner)

$(HARNESS):
       gnattest -P$(PROJECT) --subdirs=tests