3.2: Testing Workflow Instructions

Testing Workflow for AI Agents

Test Levels in ASPICE

The following diagram maps ASPICE test levels (SWE.4 unit, SWE.5 integration, SWE.6 qualification) to the AI agent's scope of automated test generation and execution.

Testing Workflow

AI Agent Scope: Unit tests (SWE.4) - automated, fast, per-commit


CI/CD Pipeline Integration

GitLab CI Example

Pipeline Configuration (.gitlab-ci.yml):

# .gitlab-ci.yml
stages:
  - build
  - unit_test
  - static_analysis
  - integration_test
  - deploy

# Stage 1: Build
build_firmware:
  stage: build
  image: gcc:11.3
  script:
    - make clean
    - make all CFLAGS="-Wall -Werror"
  artifacts:
    paths:
      - build/firmware.elf
      - build/*.o
    expire_in: 1 hour

# Stage 2: Unit Tests (AI-generated tests)
unit_tests:
  stage: unit_test
  image: gcc:11.3
  dependencies:
    - build_firmware
  script:
    # Compile unit tests
    - make test
    # Run tests with coverage
    - ./build/test_runner --gtest_output=xml:test_results.xml
    # Generate coverage report
    - gcov src/*.c
    - lcov --capture --directory . --output-file coverage.info
    - genhtml coverage.info --output-directory coverage_html
  coverage: '/Lines executed: (\d+\.\d+)%/'
  artifacts:
    reports:
      junit: test_results.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage.xml
    paths:
      - coverage_html/
      - test_results.xml
    when: always

# Stage 3: Static Analysis
misra_check:
  stage: static_analysis
  image: cppcheck:latest
  script:
    - cppcheck --addon=misra.json --xml --enable=all src/*.c 2> misra_report.xml
    - python3 scripts/parse_misra.py misra_report.xml
  artifacts:
    paths:
      - misra_report.xml
      - misra_summary.md
  allow_failure: false  # Block PR if MISRA Required violations

complexity_analysis:
  stage: static_analysis
  image: python:3.9
  script:
    - pip install radon
    - radon cc src/*.c --min B --json > complexity.json
    - python3 scripts/complexity_report.py complexity.json
  artifacts:
    paths:
      - complexity.json
      - complexity_report.md

# Stage 4: Integration Tests (if applicable)
integration_tests:
  stage: integration_test
  image: dspace-hil:latest
  script:
    - python3 tests/hil/run_integration_tests.py --xml-output=hil_results.xml
  artifacts:
    reports:
      junit: hil_results.xml
  only:
    - main  # Only run on main branch (time-consuming)

# Stage 5: Deploy (if tests pass)
deploy_to_dev:
  stage: deploy
  script:
    - scp build/firmware.elf devserver:/firmware/latest/
  only:
    - main

Unit Test Execution

Local Testing (Before Commit)

AI Agent Pre-Commit Workflow:

# Step 1: Build code
make clean && make all

# Step 2: Run unit tests
make test

# Expected output:
# [==========] Running 24 tests from 5 test suites.
# [----------] Global test environment set-up.
# [----------] 6 tests from ACC_ControllerTest
# [ RUN      ] ACC_ControllerTest.GetObstacleDistance_TypicalValue_5m
# [       OK ] ACC_ControllerTest.GetObstacleDistance_TypicalValue_5m (0 ms)
# ...
# [----------] 6 tests from ACC_ControllerTest (2 ms total)
# [==========] 24 tests from 5 test suites ran. (10 ms total)
# [  PASSED  ] 24 tests.

# Step 3: Check coverage
gcov src/*.c
# Output:
# File 'src/acc_controller.c'
# Lines executed:95.24% of 126
# Branches executed:88.46% of 26

# Step 4: If all pass, commit
if [ $? -eq 0 ]; then
    git add src/ tests/
    git commit -m "feat(acc): Implement distance calculation [ASPICE-1234]"
else
    echo "[FAIL] Tests failed, fix before committing"
fi

CI/CD Testing (After Push)

Automated Testing on Push:

# After pushing to remote:
git push origin feature/ASPICE-1234-acc-controller

# GitLab CI automatically triggers pipeline:
# ┌────────────────────────────────────────────────────┐
# │ Pipeline #142 (feature/ASPICE-1234-acc-controller) │
# ├────────────────────────────────────────────────────┤
# │ [OK] build_firmware (35s)                          │
# │ [OK] unit_tests (12s) - Coverage: 95.2%            │
# │ [OK] misra_check (8s) - 0 Required violations      │
# │ [OK] complexity_analysis (5s)                      │
# │ [--] integration_tests (skipped, not main branch)  │
# │ [--] deploy_to_dev (skipped, not main branch)      │
# └────────────────────────────────────────────────────┘
# Overall: PASSED (60s total)

# View pipeline: https://gitlab.com/company/acc-ecu/-/pipelines/142

If Pipeline Fails:

# Pipeline #142 (feature/ASPICE-1234-acc-controller)
# FAILED
#
# Stage: unit_tests
# Job: unit_tests
# Error:
# [ RUN      ] ACC_ControllerTest.GetObstacleDistance_TypicalValue_5m
# Expected: 5.0
# Actual: 5.12
# [  FAILED  ] ACC_ControllerTest.GetObstacleDistance_TypicalValue_5m (0 ms)
#
# 1 test failed out of 24

# AI Agent Action:
# 1. Analyze test failure log
# 2. Fix code or test
# 3. Commit fix, push to same branch
# 4. Pipeline re-runs automatically

Test Artifacts

What Gets Generated

1. Test Results (JUnit XML):

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="24" failures="0" errors="0" time="0.010">
  <testsuite name="ACC_ControllerTest" tests="6" failures="0" errors="0" time="0.002">
    <testcase name="GetObstacleDistance_TypicalValue_5m" time="0.000" classname="ACC_ControllerTest"/>
    <testcase name="GetObstacleDistance_BoundaryValue_0m" time="0.000" classname="ACC_ControllerTest"/>
    <testcase name="GetObstacleDistance_BoundaryValue_MaxRange" time="0.000" classname="ACC_ControllerTest"/>
    <testcase name="GetObstacleDistance_InvalidSensorData" time="0.000" classname="ACC_ControllerTest"/>
    <testcase name="GetObstacleDistance_NullPointer" time="0.000" classname="ACC_ControllerTest"/>
    <testcase name="GetObstacleDistance_CANReadFailure" time="0.000" classname="ACC_ControllerTest"/>
  </testsuite>
  <!-- More test suites... -->
</testsuites>

Usage: GitLab/GitHub parses XML, displays test results in UI


2. Coverage Report (HTML):

coverage_html/
├── index.html         # Overview (95.2% coverage)
├── acc_controller.c.html  # Line-by-line coverage (green/red highlighting)
├── can_driver.c.html
└── sensor_fusion.c.html

View Coverage:


3. MISRA Report (Markdown):

# MISRA C:2012 Compliance Report

**Date**: 2025-12-17
**Analyzed Files**: 5 files (1,200 LOC)

## Summary
| Category | Violations | Status |
|----------|------------|--------|
| **Required Rules** | 0 | PASS |
| **Advisory Rules** | 2 | WARNING |

## Required Violations (BLOCKING)
None (compliant)

## Advisory Violations (NON-BLOCKING)
1. **Rule 2.1** (Line 89, diagnostics.c): Unreachable code
   - Justification: Dead code after 'return', cleanup required
2. **Rule 8.13** (Line 156, can_driver.c): Pointer parameter should be const
   - Justification: Parameter is read-only, add const qualifier

## Recommendation
Fix Advisory violations in follow-up PR (non-blocking for merge)

Test Failure Handling

AI Agent Workflow for Test Failures

Step 1: Analyze Failure

# Read test failure log
cat test_results.xml | grep "failure"

# Example:
# <testcase name="GetObstacleDistance_TypicalValue_5m" time="0.000">
#   <failure message="Expected: 5.0, Actual: 5.12">
#     Expected: 5.0
#     Actual: 5.12
#     Test failed at tests/test_acc_controller.cpp:45
#   </failure>
# </testcase>

Step 2: Determine Root Cause

def analyze_test_failure(test_name, expected, actual):
    """
    AI agent analyzes test failure, suggests fix
    """
    difference = abs(expected - actual)
    difference_pct = (difference / expected) * 100

    if difference_pct < 1.0:
        # Small difference (<1%), likely floating-point precision issue
        return "Floating-point precision issue. Fix: Use EXPECT_NEAR with tolerance 0.1"
    elif difference_pct < 10.0:
        # Moderate difference (1-10%), likely algorithm issue
        return "Algorithm error. Check conversion formula (mm → m)"
    else:
        # Large difference (>10%), likely logic error
        return "Critical logic error. Review function implementation"

# Example
root_cause = analyze_test_failure("GetObstacleDistance_TypicalValue_5m", expected=5.0, actual=5.12)
# Output: "Algorithm error. Check conversion formula (mm → m)"

Step 3: Fix and Re-Test

# Fix code (e.g., correct formula in src/acc_controller.c)
# Original (incorrect): distance_m = radar_mm / 900.0;  // Wrong!
# Fixed: distance_m = radar_mm / 1000.0;  // Correct

# Re-run tests locally
make test

# If pass:
git add src/acc_controller.c
git commit -m "fix(acc): Correct mm-to-m conversion formula [ASPICE-1234]

- Fix: radar_mm / 1000.0 (was / 900.0)
- Resolves test failure: TC-SWE-045-1-1"

git push origin feature/ASPICE-1234-acc-controller

Step 4: Escalate if Cannot Fix

ESCALATION: Unit Test Failure (Cannot Debug)

Test: TC-SWE-045-1-1 (GetObstacleDistance_TypicalValue_5m)
Expected: 5.0 ± 0.01
Actual: 5.12 (off by 2.4%)

AI Analysis:
- Conversion formula verified: radar_mm / 1000.0 (correct)
- Mock data verified: 5000 mm (correct)
- Function logic reviewed: No obvious error

Attempts:
1. Checked formula (correct)
2. Verified test data (correct)
3. Inspected function (no issues found)

Recommendation: Human debugging required (possible floating-point issue, hardware-specific behavior)

Assignee: @senior_engineer

Test Coverage Goals

ASPICE/ISO 26262 Requirements

Safety Class Statement Coverage Branch Coverage MC/DC Coverage
QM (Non-safety) ≥80% ≥70% Not required
ASIL-A ≥90% ≥80% Not required
ASIL-B ≥100%* ≥100%* Recommended
ASIL-C/D 100% 100% Required

*Justification required for uncovered lines (hardware-dependent, proven unreachable)

AI Agent Target: Generate tests achieving at least 80% coverage (human adds edge cases to reach 100%)


Summary

Testing Workflow Key Actions:

  1. Local Testing: Run tests before commit (make test, gcov)
  2. CI/CD Pipeline: Automated testing on push (build, test, MISRA, coverage)
  3. Test Artifacts: JUnit XML, coverage HTML, MISRA report
  4. Failure Handling: Analyze, fix, re-test, escalate if needed
  5. Coverage Goals: At least 80% (AI), 100% (human completes)

Pipeline Stages: Build → Unit Test → Static Analysis → (Integration Test) → Deploy

Quality Gate: Unit tests must pass before human review

Next: Release Workflow (31.03) - Versioning, tagging, release notes