Testes Automatizados com Ada: Estratégias e Ferramentas para Sistemas Críticos

Visão geral da linguagem

Ada foi concebida para oferecer verificação estática agressiva, coerência de tipos e facilidades de concorrência integradas. Esses atributos tornam a linguagem particularmente adequada para domínios onde falhas custam vidas ou milhões de dólares. A tipagem forte impede que valores incompatíveis sejam atribuídos acidentalmente, enquanto o sistema de pacotes e genéricos permite modelar domínios complexos sem perder segurança.

Por que testar software Ada?

Mesmo com o suporte estático robusto, testes continuam necessários para validar requisitos funcionais, desempenho e comportamento em cenários de falha. Em sistemas certificáveis (DO-178C, ECSS-Q-80), o nível de cobertura exigido (MC/DC, branch, statement) torna o planejamento de teste uma atividade tão crítica quanto o próprio código.

Organizando testes com Alire e AUnit

O ecossistema Alire (Ada Library Repository) simplifica a gestão de dependências. Para criar um projeto de teste:

alr init --bin sistema_demo
cd sistema_demo
alr with aunit

Com AUnit, cada caso de teste herita de AUnit.Test_Cases.Test_Case. Abaixo, um exemplo que valida uma rotina de controle de altitude:

with AUnit.Test_Cases; use AUnit.Test_Cases;
with AUnit.Assertions; use AUnit.Assertions;

package Ctrl.Altitude.Tests is
   type Altitude_Test is new Test_Case with null record;
   procedure Register_Tests (T : in out Altitude_Test);
   function Name (T : Altitude_Test) return String;
end Ctrl.Altitude.Tests;

package body Ctrl.Altitude.Tests is
   function Name (T : Altitude_Test) return String is ("Altitude Control");

   procedure Test_Pid_Stability (T : in out TC) is
      Target : constant := 10_000; -- pés
      Actual : Altitude_Type;
   begin
      Actual := Compute_Correction (Target, Current => 9_800);
      Assert (abs (Target - Actual) < 50, "Oscilação excessiva");
   end Test_Pid_Stability;

   procedure Register_Tests (T : in out Altitude_Test) is
   begin
      Register_Routine (T, Test_Pid_Stability'Access, "PID Stable");
   end Register_Tests;
end Ctrl.Altitude.Tests;

Para executar:

alr build
alr exec -- ./bin/sistema_demo

Mockando dependências externas

Sensores e atuadores frequentemente não estão disponíveis durante os testes. Utilize interfaces e genéricos para injetar comportamentos simulados:

generic
   type Reading is private;
   with function Raw_Sensor return Reading;
package Sensors.Mock is
   procedure Override_Value (V : Reading);
end Sensors.Mock;

package body Sensors.Mock is
   Simulated : Reading;
   procedure Override_Value (V : Reading) is begin Simulated := V; end;
   function Raw_Sensor return Reading is (Simulated);
end Sensors.Mock;

Durante a execução de teste, basta chamar Override_Value para forçar cenários de falha ou limite.

Integração contínua com GitHub Actions

Um workflow mínimo para rodar testes em cada push:

name: ci
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: alire-project/setup-alire@v2
      - run: alr build --release
      - run: alr exec -- aunit-runner --output xml
      - uses: dorny/test-reporter@v1
        with:
          path: "*.xml"
          reporter: java-junit

Medindo cobertura com gcov + gprbuild

Compile com sinalizadores de instrumentação:

gprbuild -P sistema_demo.gpr -cargs -fprofile-arcs -ftest-coverage \
         -largs -lgcov

Após rodar os testes, gere o relatório:

gcovr --html-details cov.html

Testes de concorrência com tasking

Validar interleavings é desafiador. A estratégia é isolar a lógica de sincronização em protected objects e usar pragma Priority para forçar ordem específica:

protected type Channel (Size : Positive) is
   entry Send (Item : Message);
   entry Receive (Item : out Message);
private
   Buffer : Message_Array (1 .. Size);
   Head, Tail : Index := 1;
   Count : Natural := 0;
end Channel;

Testes podem então verificar condições de corrida alterando prioridades dinamicamente via Ada.Dynamic_Priorities.

Relatórios certificáveis

Ferramentas como GNATcoverage exportam dados compatíveis com o SCADE Test ou VectorCAST, permitindo rastreabilidade bidirecional entre requisitos, código-fonte e casos de teste — mandatório para auditorais DO-178C nível A.

Tags: ada aunit alire gcovr do-178c

Publicado em 9-19 04:50