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.