Automatisierte ATC-Prüfungen sind unverzichtbar für kontinuierliche Code-Qualität in SAP BTP ABAP Environment. Während du im Entwicklungsalltag ATC manuell in ADT ausführst, ermöglicht die ATC API die Integration in CI/CD-Pipelines für automatisierte Quality Gates.
Warum ATC automatisieren?
Die manuelle Ausführung von ATC-Prüfungen hat Grenzen:
| Aspekt | Manuell | Automatisiert |
|---|---|---|
| Timing | Vor Transport | Bei jedem Commit |
| Konsistenz | Entwicklerabhängig | Immer gleiche Checks |
| Vergessen | Möglich | Unmöglich |
| Reporting | Punktuell | Kontinuierlich |
| Trend-Analyse | Nicht möglich | Historische Daten |
| Teamstandard | Schwer durchsetzbar | Automatisch erzwungen |
┌────────────────────────────────────────────────────────────────┐│ CI/CD Pipeline mit ATC Quality Gate │├────────────────────────────────────────────────────────────────┤│ ││ Git Push ──▶ Build ──▶ ABAP Unit ──▶ ATC API ──▶ Deploy ││ Tests Checks ││ │ ││ ▼ ││ ┌──────────────┐ ││ │ Quality │ ││ │ Gate │ ││ │ ──────────── │ ││ │ Errors: 0 │ ││ │ Warnings: <5 │ ││ └──────────────┘ ││ │└────────────────────────────────────────────────────────────────┘Voraussetzungen
Bevor du die ATC API nutzen kannst, benötigst du:
- SAP BTP ABAP Environment (Steampunk-Instanz)
- Communication Arrangement für ADT-Services (SAP_COM_0763)
- Communication User mit entsprechenden Berechtigungen
- Check-Variante für die automatisierte Ausführung
Communication Arrangement einrichten
Das Communication Arrangement aus dem ABAP Unit Runner gilt auch für ATC:
┌────────────────────────────────────────────────────────────────┐│ Communication Arrangement: SAP_COM_0763 │├────────────────────────────────────────────────────────────────┤│ ││ Inbound Services (aktiviert): ││ ☑ ADT Core Services ││ ☑ ADT ABAP Unit ││ ☑ ADT ATC (ABAP Test Cockpit) ││ ││ Erforderliche Berechtigungen: ││ • S_DEVELOP (Entwicklungsobjekte lesen) ││ • S_ATC_ADM (ATC Administration) ││ │└────────────────────────────────────────────────────────────────┘ATC API auf BTP
Die ATC API basiert auf dem ADT REST Framework und ermöglicht die programmatische Ausführung von ATC-Prüfungen.
API-Endpunkt
POST https://<system-url>/sap/bc/adt/atc/runsRequest-Format
<?xml version="1.0" encoding="UTF-8"?><atc:run xmlns:atc="http://www.sap.com/adt/atc" xmlns:adtcore="http://www.sap.com/adt/core" maximumVerdicts="100"> <objectSets> <objectSet kind="inclusive"> <adtcore:objectReferences> <adtcore:objectReference adtcore:uri="/sap/bc/adt/vit/wb/object_type/devck/object_name/Z_FLIGHT_BOOKING"/> </adtcore:objectReferences> </objectSet> </objectSets> <checkVariant> <atc:name>ABAP_CLOUD_READINESS</atc:name> </checkVariant></atc:run>Wichtige Request-Parameter
| Parameter | Beschreibung | Beispiel |
|---|---|---|
| maximumVerdicts | Max. Anzahl Findings | 100, 500, 1000 |
| objectReference | Zu prüfendes Objekt (Paket, Klasse) | devck/Z_FLIGHT_BOOKING |
| checkVariant | Check-Variante | ABAP_CLOUD_READINESS |
cURL-Beispiel
# ATC-Prüfung für ein Paket startencurl -X POST \ "https://my-system.abap.eu10.hana.ondemand.com/sap/bc/adt/atc/runs" \ -u "CICD_USER:password" \ -H "Content-Type: application/vnd.sap.atc.run.v1+xml" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ -d @atc_config.xml \ -o atc_results.xmlEigene Check-Varianten definieren
Check-Varianten bestimmen, welche Prüfungen mit welcher Priorität ausgeführt werden.
Standard Check-Varianten auf BTP
| Variante | Beschreibung | Empfohlen für |
|---|---|---|
| ABAP_CLOUD_READINESS | Prüft Cloud-Kompatibilität | Migration zu ABAP Cloud |
| DEFAULT | Alle Standard-Checks | Allgemeine Qualität |
| SAP_CP | SAP Cloud Platform Checks | BTP-Entwicklung |
Check-Variante per API abrufen
# Verfügbare Check-Varianten abfragencurl -X GET \ "https://my-system.abap.eu10.hana.ondemand.com/sap/bc/adt/atc/customizing/variants" \ -u "CICD_USER:password" \ -H "Accept: application/vnd.sap.atc.customizing.v1+xml"Eigene Check-Variante anlegen
In SAP BTP ABAP Environment legst du Check-Varianten über die Fiori App Maintain ATC Check Variants an:
┌────────────────────────────────────────────────────────────────┐│ Check-Variante: Z_CI_PIPELINE │├────────────────────────────────────────────────────────────────┤│ ││ Beschreibung: Check-Variante für CI/CD Pipeline ││ ││ ┌────────────────────────────────────────────────────────────┐ ││ │ Check │ Priorität │ Aktiv │ ││ ├────────────────────────────────┼───────────┼──────────────┤ ││ │ SLIN_CHECK (Syntax Check) │ 1 │ ☑ │ ││ │ SEC_CHECK (Security) │ 1 │ ☑ │ ││ │ PERF_CHECK (Performance) │ 2 │ ☑ │ ││ │ CONV_CHECK (Conventions) │ 3 │ ☑ │ ││ │ CLOUD_CHECK (Cloud Readiness) │ 1 │ ☑ │ ││ │ UNIT_TEST (Unit Tests) │ 2 │ ☐ │ ││ └────────────────────────────────┴───────────┴──────────────┘ ││ ││ Prioritäten-Einstellung: ││ • Priorität 1 (Fehler) → Build bricht ab ││ • Priorität 2 (Warning) → Build mit Warnung ││ • Priorität 3 (Info) → Nur protokolliert ││ │└────────────────────────────────────────────────────────────────┘Check-Kategorien im Detail
" Die wichtigsten Check-Kategorien für ABAP Cloud:
" 1. Cloud Readiness Checks" - Verwendung von nicht-freigegebenen APIs" - Direkte DB-Zugriffe (SELECT auf Standardtabellen)" - Verwendung von Dynpro-Anweisungen
" 2. Security Checks" - SQL Injection Risiken" - Cross-Site Scripting (XSS)" - Fehlende Authority Checks" - Hardcodierte Credentials
" 3. Performance Checks" - SELECT * vermeiden" - Schleifen mit SELECT" - Fehlende WHERE-Klauseln" - LOOP AT ohne READ TABLE Alternative
" 4. Naming Convention Checks" - Z/Y Prefix für Custom Objects" - Naming Guidelines für Variablen" - Package-ZuordnungAutomatische Ausführung einrichten
Zweistufiger ATC-Prozess
Die ATC API arbeitet asynchron - du startest einen Run und fragst die Ergebnisse ab:
┌─────────────────────────────────────────────────────────────────┐│ ATC API Workflow │├─────────────────────────────────────────────────────────────────┤│ ││ 1. POST /sap/bc/adt/atc/runs ││ ├─ Request: Check-Konfiguration ││ └─ Response: Run-ID (Location Header) ││ ││ 2. Polling: GET /sap/bc/adt/atc/runs/{run-id} ││ ├─ Status: running → warten ││ └─ Status: finished → Ergebnisse abrufen ││ ││ 3. GET /sap/bc/adt/atc/runs/{run-id}/results ││ └─ Response: Findings als XML ││ │└─────────────────────────────────────────────────────────────────┘Vollständiges Bash-Script für ATC-Ausführung
#!/bin/bash# run_atc.sh - ATC-Prüfung auf BTP ausführen
set -e
# KonfigurationSYSTEM_URL="${ABAP_ENDPOINT}"USER="${ABAP_USER}"PASSWORD="${ABAP_PASSWORD}"PACKAGE="${1:-Z_FLIGHT_BOOKING}"CHECK_VARIANT="${2:-ABAP_CLOUD_READINESS}"MAX_VERDICTS="${3:-500}"
echo "=== Starting ATC Check ==="echo "Package: $PACKAGE"echo "Variant: $CHECK_VARIANT"
# 1. ATC Run startencat > atc_request.xml << EOF<?xml version="1.0" encoding="UTF-8"?><atc:run xmlns:atc="http://www.sap.com/adt/atc" xmlns:adtcore="http://www.sap.com/adt/core" maximumVerdicts="$MAX_VERDICTS"> <objectSets> <objectSet kind="inclusive"> <adtcore:objectReferences> <adtcore:objectReference adtcore:uri="/sap/bc/adt/vit/wb/object_type/devck/object_name/$PACKAGE"/> </adtcore:objectReferences> </objectSet> </objectSets> <checkVariant> <atc:name>$CHECK_VARIANT</atc:name> </checkVariant></atc:run>EOF
# Run starten und Location Header extrahierenRESPONSE=$(curl -s -D - \ -X POST \ "$SYSTEM_URL/sap/bc/adt/atc/runs" \ -u "$USER:$PASSWORD" \ -H "Content-Type: application/vnd.sap.atc.run.v1+xml" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ -d @atc_request.xml)
RUN_ID=$(echo "$RESPONSE" | grep -i "location:" | sed 's/.*runs\///' | tr -d '\r\n')
if [ -z "$RUN_ID" ]; then echo "::error::Failed to start ATC run" echo "$RESPONSE" exit 1fi
echo "ATC Run started: $RUN_ID"
# 2. Auf Abschluss warten (Polling)MAX_ATTEMPTS=60ATTEMPT=0
while [ $ATTEMPT -lt $MAX_ATTEMPTS ]; do STATUS_RESPONSE=$(curl -s \ -X GET \ "$SYSTEM_URL/sap/bc/adt/atc/runs/$RUN_ID" \ -u "$USER:$PASSWORD" \ -H "Accept: application/vnd.sap.atc.run.v1+xml")
STATUS=$(echo "$STATUS_RESPONSE" | grep -oP 'status="\K[^"]+' || echo "unknown")
echo "Status: $STATUS (Attempt $((ATTEMPT+1))/$MAX_ATTEMPTS)"
if [ "$STATUS" = "finished" ]; then break fi
sleep 5 ATTEMPT=$((ATTEMPT+1))done
if [ "$STATUS" != "finished" ]; then echo "::error::ATC run timed out" exit 1fi
# 3. Ergebnisse abrufencurl -s \ -X GET \ "$SYSTEM_URL/sap/bc/adt/atc/runs/$RUN_ID/results" \ -u "$USER:$PASSWORD" \ -H "Accept: application/vnd.sap.atc.worklist.v1+xml" \ -o atc_results.xml
echo "=== ATC Results saved to atc_results.xml ==="Ergebnisse auswerten und reporten
ATC Response-Format
<?xml version="1.0" encoding="UTF-8"?><atc:worklist xmlns:atc="http://www.sap.com/adt/atc" xmlns:adtcore="http://www.sap.com/adt/core" timestamp="2026-02-15T10:30:00Z" usedCheckVariant="Z_CI_PIPELINE"> <objects> <object adtcore:uri="/sap/bc/adt/oo/classes/zcl_flight_booking" adtcore:name="ZCL_FLIGHT_BOOKING" adtcore:type="CLAS"> <findings> <finding checkId="CL_CI_CRITICAL_API_USE" checkTitle="Non-released API usage" messageId="001" messageTitle="Usage of non-released API detected" priority="1" location="/sap/bc/adt/oo/classes/zcl_flight_booking/source/main#start=45,10"> <atc:quickfixes count="1"/> </finding> <finding checkId="CL_CI_SEC_INJECTION" checkTitle="SQL Injection Risk" messageId="002" messageTitle="Potential SQL injection vulnerability" priority="1" location="/sap/bc/adt/oo/classes/zcl_flight_booking/source/main#start=78,5"> <atc:quickfixes count="0"/> </finding> <finding checkId="CL_CI_CONV_NAMING" checkTitle="Naming Convention" messageId="003" messageTitle="Variable naming does not follow convention" priority="3" location="/sap/bc/adt/oo/classes/zcl_flight_booking/source/main#start=12,8"> <atc:quickfixes count="1"/> </finding> </findings> </object> </objects> <statistics> <totalFindings>3</totalFindings> <findingsByPriority> <priority1>2</priority1> <priority2>0</priority2> <priority3>1</priority3> </findingsByPriority> </statistics></atc:worklist>Python-Script für Ergebnis-Parsing
import xml.etree.ElementTree as ETimport sysimport jsonfrom dataclasses import dataclass, asdictfrom typing import List
@dataclassclass Finding: check_id: str check_title: str message: str priority: int object_name: str location: str has_quickfix: bool
def parse_atc_results(xml_file: str) -> dict: tree = ET.parse(xml_file) root = tree.getroot()
ns = { 'atc': 'http://www.sap.com/adt/atc', 'adtcore': 'http://www.sap.com/adt/core' }
findings: List[Finding] = [] priority_counts = {1: 0, 2: 0, 3: 0}
for obj in root.findall('.//atc:object', ns): obj_name = obj.get('{http://www.sap.com/adt/core}name', 'Unknown')
for finding in obj.findall('.//atc:finding', ns): priority = int(finding.get('priority', 3)) priority_counts[priority] = priority_counts.get(priority, 0) + 1
quickfixes = finding.find('atc:quickfixes', ns) has_quickfix = quickfixes is not None and int(quickfixes.get('count', 0)) > 0
findings.append(Finding( check_id=finding.get('checkId', ''), check_title=finding.get('checkTitle', ''), message=finding.get('messageTitle', ''), priority=priority, object_name=obj_name, location=finding.get('location', ''), has_quickfix=has_quickfix ))
return { 'total': len(findings), 'errors': priority_counts.get(1, 0), 'warnings': priority_counts.get(2, 0), 'info': priority_counts.get(3, 0), 'findings': [asdict(f) for f in findings] }
def print_report(results: dict, error_threshold: int = 0, warning_threshold: int = 5): print("=" * 60) print("ATC QUALITY REPORT") print("=" * 60) print(f"Total Findings: {results['total']}") print(f" Errors (P1): {results['errors']}") print(f" Warnings (P2): {results['warnings']}") print(f" Info (P3): {results['info']}") print("=" * 60)
# Findings nach Priorität gruppiert ausgeben for priority in [1, 2, 3]: priority_findings = [f for f in results['findings'] if f['priority'] == priority] if priority_findings: print(f"\nPriority {priority} Findings:") print("-" * 40) for f in priority_findings: print(f" [{f['check_id']}] {f['object_name']}") print(f" {f['message']}") quickfix = "✓ Quickfix available" if f['has_quickfix'] else "" print(f" {f['location']} {quickfix}")
print("\n" + "=" * 60)
# Thresholds prüfen exit_code = 0 if results['errors'] > error_threshold: print(f"::error::Found {results['errors']} error(s) (threshold: {error_threshold})") exit_code = 1
if results['warnings'] > warning_threshold: print(f"::warning::Found {results['warnings']} warning(s) (threshold: {warning_threshold})")
return exit_code
if __name__ == '__main__': if len(sys.argv) < 2: print("Usage: python parse_atc_results.py <xml_file> [--json]") sys.exit(1)
results = parse_atc_results(sys.argv[1])
if '--json' in sys.argv: print(json.dumps(results, indent=2)) else: exit_code = print_report(results) sys.exit(exit_code)Integration mit GitHub/GitLab
GitHub Actions Workflow
name: ATC Quality Gate
on: push: branches: [ main, develop ] pull_request: branches: [ main ]
env: PACKAGE: Z_FLIGHT_BOOKING CHECK_VARIANT: ABAP_CLOUD_READINESS ERROR_THRESHOLD: 0 WARNING_THRESHOLD: 5
jobs: atc-check: name: ATC Quality Check runs-on: ubuntu-latest
steps: - name: Checkout uses: actions/checkout@v4
- name: Setup Python uses: actions/setup-python@v5 with: python-version: '3.11'
- name: Create ATC Configuration run: | cat > atc_config.xml << 'EOF' <?xml version="1.0" encoding="UTF-8"?> <atc:run xmlns:atc="http://www.sap.com/adt/atc" xmlns:adtcore="http://www.sap.com/adt/core" maximumVerdicts="500"> <objectSets> <objectSet kind="inclusive"> <adtcore:objectReferences> <adtcore:objectReference adtcore:uri="/sap/bc/adt/vit/wb/object_type/devck/object_name/${{ env.PACKAGE }}"/> </adtcore:objectReferences> </objectSet> </objectSets> <checkVariant> <atc:name>${{ env.CHECK_VARIANT }}</atc:name> </checkVariant> </atc:run> EOF
- name: Start ATC Run id: start-atc run: | RESPONSE=$(curl -s -D - \ -X POST \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/atc/runs" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Content-Type: application/vnd.sap.atc.run.v1+xml" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ -d @atc_config.xml)
RUN_ID=$(echo "$RESPONSE" | grep -i "location:" | sed 's/.*runs\///' | tr -d '\r\n')
if [ -z "$RUN_ID" ]; then echo "::error::Failed to start ATC run" exit 1 fi
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT echo "Started ATC run: $RUN_ID"
- name: Wait for ATC Completion run: | RUN_ID="${{ steps.start-atc.outputs.run_id }}" MAX_ATTEMPTS=60
for i in $(seq 1 $MAX_ATTEMPTS); do STATUS=$(curl -s \ -X GET \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/atc/runs/$RUN_ID" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ | grep -oP 'status="\K[^"]+' || echo "unknown")
echo "Status: $STATUS (Attempt $i/$MAX_ATTEMPTS)"
if [ "$STATUS" = "finished" ]; then break fi
sleep 5 done
if [ "$STATUS" != "finished" ]; then echo "::error::ATC run timed out" exit 1 fi
- name: Fetch ATC Results run: | RUN_ID="${{ steps.start-atc.outputs.run_id }}"
curl -s \ -X GET \ "${{ secrets.ABAP_ENDPOINT }}/sap/bc/adt/atc/runs/$RUN_ID/results" \ -u "${{ secrets.ABAP_USER }}:${{ secrets.ABAP_PASSWORD }}" \ -H "Accept: application/vnd.sap.atc.worklist.v1+xml" \ -o atc_results.xml
- name: Parse and Evaluate Results id: parse run: | python << 'PYTHON_SCRIPT' import xml.etree.ElementTree as ET import os
tree = ET.parse('atc_results.xml') root = tree.getroot() ns = {'atc': 'http://www.sap.com/adt/atc', 'adtcore': 'http://www.sap.com/adt/core'}
errors = warnings = info = 0
for finding in root.findall('.//atc:finding', ns): priority = int(finding.get('priority', 3)) if priority == 1: errors += 1 elif priority == 2: warnings += 1 else: info += 1
with open(os.environ['GITHUB_OUTPUT'], 'a') as f: f.write(f"errors={errors}\n") f.write(f"warnings={warnings}\n") f.write(f"info={info}\n") f.write(f"total={errors + warnings + info}\n")
print(f"Errors: {errors}, Warnings: {warnings}, Info: {info}")
# Quality Gate prüfen if errors > int(os.environ.get('ERROR_THRESHOLD', 0)): print(f"::error::Quality Gate failed: {errors} error(s) found") exit(1) PYTHON_SCRIPT
- name: Upload ATC Results uses: actions/upload-artifact@v4 with: name: atc-results path: atc_results.xml
- name: Create Summary if: always() run: | cat >> $GITHUB_STEP_SUMMARY << EOF ## ATC Quality Gate Results
| Metric | Value | Threshold | |--------|-------|-----------| | Errors (P1) | ${{ steps.parse.outputs.errors }} | ${{ env.ERROR_THRESHOLD }} | | Warnings (P2) | ${{ steps.parse.outputs.warnings }} | ${{ env.WARNING_THRESHOLD }} | | Info (P3) | ${{ steps.parse.outputs.info }} | - | | **Total** | ${{ steps.parse.outputs.total }} | |
**Status:** ${{ steps.parse.outputs.errors == 0 && '✅ Passed' || '❌ Failed' }} EOFGitLab CI/CD Pipeline
stages: - quality
variables: PACKAGE: Z_FLIGHT_BOOKING CHECK_VARIANT: ABAP_CLOUD_READINESS ERROR_THRESHOLD: "0"
atc-quality-gate: stage: quality image: python:3.11-slim before_script: - apt-get update && apt-get install -y curl script: # ATC Run starten - | RESPONSE=$(curl -s -D - \ -X POST \ "${ABAP_ENDPOINT}/sap/bc/adt/atc/runs" \ -u "${ABAP_USER}:${ABAP_PASSWORD}" \ -H "Content-Type: application/vnd.sap.atc.run.v1+xml" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ -d "<atc:run xmlns:atc=\"http://www.sap.com/adt/atc\" xmlns:adtcore=\"http://www.sap.com/adt/core\" maximumVerdicts=\"500\"> <objectSets> <objectSet kind=\"inclusive\"> <adtcore:objectReferences> <adtcore:objectReference adtcore:uri=\"/sap/bc/adt/vit/wb/object_type/devck/object_name/${PACKAGE}\"/> </adtcore:objectReferences> </objectSet> </objectSets> <checkVariant> <atc:name>${CHECK_VARIANT}</atc:name> </checkVariant> </atc:run>")
RUN_ID=$(echo "$RESPONSE" | grep -i "location:" | sed 's/.*runs\///' | tr -d '\r\n') echo "ATC Run ID: $RUN_ID"
# Auf Abschluss warten - | for i in $(seq 1 60); do STATUS=$(curl -s \ "${ABAP_ENDPOINT}/sap/bc/adt/atc/runs/${RUN_ID}" \ -u "${ABAP_USER}:${ABAP_PASSWORD}" \ -H "Accept: application/vnd.sap.atc.run.v1+xml" \ | grep -oP 'status="\K[^"]+' || echo "unknown")
echo "Attempt $i: Status = $STATUS" [ "$STATUS" = "finished" ] && break sleep 5 done
# Ergebnisse abrufen - | curl -s \ "${ABAP_ENDPOINT}/sap/bc/adt/atc/runs/${RUN_ID}/results" \ -u "${ABAP_USER}:${ABAP_PASSWORD}" \ -H "Accept: application/vnd.sap.atc.worklist.v1+xml" \ -o atc_results.xml
# Ergebnisse prüfen - | python3 << 'EOF' import xml.etree.ElementTree as ET import sys import os
tree = ET.parse('atc_results.xml') root = tree.getroot() ns = {'atc': 'http://www.sap.com/adt/atc'}
errors = sum(1 for f in root.findall('.//atc:finding', ns) if f.get('priority') == '1') print(f"Found {errors} error(s)")
if errors > int(os.environ.get('ERROR_THRESHOLD', 0)): sys.exit(1) EOF artifacts: paths: - atc_results.xml reports: junit: atc_results.xml when: always rules: - if: $CI_PIPELINE_SOURCE == "merge_request_event" - if: $CI_COMMIT_BRANCH == "main"Best Practices
| Aspekt | Empfehlung |
|---|---|
| Check-Variante | Eigene Variante für CI/CD mit klaren Prioritäten |
| Error-Threshold | 0 für Priority 1 (keine Fehler erlaubt) |
| Warning-Threshold | Realistisch setzen, schrittweise senken |
| Timeout | Max. 5 Minuten für große Pakete |
| Quickfixes | In Report anzeigen, nicht automatisch anwenden |
| Trend-Tracking | Findings über Zeit protokollieren |
| Team-Standards | Check-Variante im Team abstimmen |
| Exception-Handling | Berechtigte Ausnahmen dokumentieren |
Troubleshooting
| Problem | Mögliche Ursache | Lösung |
|---|---|---|
| 401 Unauthorized | Falsche Credentials | User/Passwort prüfen |
| 403 Forbidden | Fehlende ATC-Berechtigung | S_ATC_ADM prüfen |
| 404 Not Found | Paket/Variante existiert nicht | Namen prüfen |
| Timeout | Paket zu groß | In kleinere Pakete aufteilen |
| Keine Findings | Check-Variante leer | Checks in Variante aktivieren |
| Run bleibt “running” | System überlastet | Später erneut versuchen |
Weiterführende Ressourcen
- ABAP Test Cockpit - ATC Grundlagen und manuelle Nutzung
- ABAP Unit Runner auf BTP - Unit Tests automatisiert ausführen
- CI/CD mit ABAP Cloud - Vollständige Pipeline-Konzepte
- Clean Core Strategie - Qualitätsstandards für ABAP Cloud