← Back to DevBytes

Helix Testing Integration: Complete Guide

Understanding Helix Testing Integration

Helix Testing Integration refers to the systematic connection between Helix ALM (Application Lifecycle Management) — formerly known as TestTrack — and your software testing ecosystem. It bridges test management, automated test execution, continuous integration pipelines, and version control to create a unified quality assurance workflow. At its core, the integration enables teams to plan test cases, track execution results, link tests to source code changes, and generate compliance-ready audit trails — all within a single pane of glass.

The Helix ALM suite provides a REST API, webhooks, and native CI plugin interfaces that allow developers and QA engineers to push test results from any framework — JUnit, pytest, Selenium, Cypress, Playwright, or custom scripts — directly into Helix Test Management. This eliminates manual result entry, reduces human error, and accelerates feedback loops across the development lifecycle.

Key Components of the Integration

Why Helix Testing Integration Matters

🚀 Deploy your AI agent in 10 minutes

Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.

Try it free →

Without integration, test results live in isolated silos. A CI pipeline might run 2,000 tests, produce a JUnit XML report, and then sit idle while someone manually transcribes pass/fail counts into a test management tool. That gap introduces latency, miscounts, and a loss of traceability that becomes catastrophic during audits or release sign-off. Helix Testing Integration solves this by automating the flow of data end-to-end.

Benefits at a Glance

Architecture and Data Flow

Before diving into code, it's helpful to understand the typical integration architecture. The diagram below (described textually) illustrates how data moves between systems:

┌─────────────────────┐     REST API / tccli      ┌──────────────────────────┐
│   CI/CD Pipeline    │ ─────────────────────────▶ │   Helix ALM Server       │
│  (Jenkins, GitLab,  │                            │                          │
│   GitHub Actions,   │                            │  ┌────────────────────┐  │
│   Azure DevOps)     │                            │  │  Test Cases        │  │
└─────────────────────┘                            │  │  Test Runs         │  │
         │                                        │  │  Requirements      │  │
         │                                        │  │  Issues / Bugs     │  │
         ▼                                        │  └────────────────────┘  │
┌─────────────────────┐                            │                          │
│   Test Frameworks   │                            │  Source Control Linkage  │
│  (JUnit, pytest,    │                            │  (Helix Core / Git)      │
│   Selenium, etc.)   │                            └──────────────────────────┘
└─────────────────────┘                                        │
         │                                                     │
         ▼                                                     ▼
┌─────────────────────┐                            ┌──────────────────────────┐
│  JUnit XML / JSON   │                            │  Helix Core / Git Repo   │
│  Test Results       │                            │  (source code, changelists)│
└─────────────────────┘                            └──────────────────────────┘

Getting Started: Prerequisites

To follow along with the code examples, ensure you have:

Installing and Configuring tccli

The Helix Command-Line Interface client is the most versatile tool for integration. Install it on your CI build agent or developer workstation:

# Download the tccli package for your platform from Perforce's download site
# Example for Linux x64:
wget https://ftp.perforce.com/helix-alm/cli/r2024.1/tccli-r2024.1-linux-x64.tar.gz

# Extract and place on PATH
tar -xzf tccli-r2024.1-linux-x64.tar.gz
sudo cp tccli /usr/local/bin/
sudo chmod +x /usr/local/bin/tccli

# Verify installation
tccli --version
# Output: Helix ALM CLI Client version 2024.1.0

Next, configure authentication. You can use a profile file or environment variables:

# Create a configuration profile (recommended for CI environments)
tccli config --server https://helix-server.example.com:8443 \
             --username svc_test_integration \
             --password-file /secure/helix-password.txt \
             --project "ProjectAlpha" \
             --profile ci-integration

# Alternatively, use environment variables for ephemeral CI jobs
export HELIX_SERVER_URL="https://helix-server.example.com:8443"
export HELIX_USERNAME="svc_test_integration"
export HELIX_PASSWORD="$(cat /secure/helix-password.txt)"
export HELIX_PROJECT="ProjectAlpha"

Core Integration Workflows with Code Examples

Workflow 1: Creating and Executing a Test Run from CI

The most common workflow involves: (1) retrieving a predefined test suite or filter from Helix, (2) executing the tests in your pipeline, and (3) pushing results back to Helix as a completed test run.

Step 1: Query test cases from Helix using the REST API. You can filter by requirement, test folder, or labels:

# Use curl to fetch test cases that are tagged for smoke testing
curl -X GET \
  "https://helix-server.example.com:8443/rest/api/v1/testcases?filter=labels%3A%22smoke%22&fields=id,name,description" \
  -H "Authorization: Basic $(echo -n 'svc_test_integration:YourPassword' | base64)" \
  -H "Accept: application/json" \
  -o smoke_tests.json

# Sample response (smoke_tests.json):
# {
#   "data": [
#     {"id": "TC-1001", "name": "Login Page Smoke Test", "description": "..."},
#     {"id": "TC-1002", "name": "Dashboard Load Smoke Test", "description": "..."},
#     ...
#   ],
#   "totalResults": 12
# }

Step 2: Create a new test run in Helix, associating it with these test cases. The test run will be the container for results:

# Create a new test run via REST API
curl -X POST \
  "https://helix-server.example.com:8443/rest/api/v1/testruns" \
  -H "Authorization: Basic $(echo -n 'svc_test_integration:YourPassword' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Nightly Smoke - Build #247 - 2025-06-15",
    "testcaseIds": ["TC-1001", "TC-1002", "TC-1003", "TC-1004"],
    "status": "InProgress",
    "buildNumber": "247",
    "environment": "Staging-US-East"
  }' \
  -o created_run.json

# Extract the test run ID from the response
RUN_ID=$(jq -r '.id' created_run.json)
echo "Created Test Run ID: $RUN_ID"
# Output: Created Test Run ID: TR-5890

Step 3: Execute your actual tests (this is framework-dependent). The key is to produce structured output that can be parsed:

# Run pytest and generate JUnit XML output
cd /workspace/tests
pytest smoke_tests/ --junitxml=smoke_results.xml -v

# Alternatively, for a JavaScript project:
# npx playwright test --grep="@smoke" --reporter=junit --output=smoke_results.xml

Step 4: Parse the test result file and submit individual test case results to Helix. This script reads JUnit XML, maps test names to Helix test case IDs, and updates the test run:

#!/usr/bin/env python3
"""
submit_results.py - Parse JUnit XML and push results to Helix ALM
"""

import xml.etree.ElementTree as ET
import requests
import sys
import os

# --- Configuration ---
HELIX_SERVER = os.environ.get("HELIX_SERVER_URL")
HELIX_USER = os.environ.get("HELIX_USERNAME")
HELIX_PASS = os.environ.get("HELIX_PASSWORD")
RUN_ID = os.environ.get("RUN_ID")  # TR-5890 from previous step
RESULTS_FILE = "smoke_results.xml"

# --- Mapping: JUnit test name -> Helix Test Case ID ---
# In practice, this mapping is derived from test annotations or a config file
TEST_CASE_MAP = {
    "test_login_success": "TC-1001",
    "test_login_failure": "TC-1002",   # Note: two JUnit tests can map to same Helix TC
    "test_dashboard_load": "TC-1003",
    "test_user_profile_edit": "TC-1004",
}

def parse_junit_xml(filepath):
    """Parse JUnit XML and return a list of {name, classname, result, message} dicts."""
    tree = ET.parse(filepath)
    root = tree.getroot()
    results = []
    
    for testcase in root.iter('testcase'):
        name = testcase.get('name')
        classname = testcase.get('classname')
        full_name = f"{classname}.{name}" if classname else name
        
        # Check for failure, error, or skipped child elements
        failure = testcase.find('failure')
        error = testcase.find('error')
        skipped = testcase.find('skipped')
        
        if failure is not None:
            result = "Failed"
            message = failure.get('message') or failure.text or "Test failed"
        elif error is not None:
            result = "Error"
            message = error.get('message') or error.text or "Test error"
        elif skipped is not None:
            result = "Skipped"
            message = skipped.get('message') or "Test skipped"
        else:
            result = "Passed"
            message = ""
        
        results.append({
            "name": name,
            "full_name": full_name,
            "result": result,
            "message": message
        })
    
    return results

def update_helix_test_run_result(run_id, test_case_id, verdict, comment=""):
    """Update a single test case result within a Helix test run."""
    url = f"{HELIX_SERVER}/rest/api/v1/testruns/{run_id}/results"
    payload = {
        "testcaseId": test_case_id,
        "verdict": verdict,       # "Passed", "Failed", "Error", "Skipped", "Blocked"
        "actualResults": comment,
        "executedBy": HELIX_USER,
        "executionTime": 0        # Optional: set actual execution time in seconds
    }
    
    response = requests.post(
        url,
        json=payload,
        auth=(HELIX_USER, HELIX_PASS),
        headers={"Content-Type": "application/json"}
    )
    
    if response.status_code not in (200, 201):
        print(f"ERROR updating TC {test_case_id}: {response.status_code} - {response.text}")
    else:
        print(f"Updated TC {test_case_id} -> {verdict}")

# --- Main Execution ---
if __name__ == "__main__":
    if not RUN_ID:
        print("ERROR: RUN_ID environment variable not set")
        sys.exit(1)
    
    junit_results = parse_junit_xml(RESULTS_FILE)
    
    for test_result in junit_results:
        test_name = test_result["name"]
        if test_name in TEST_CASE_MAP:
            tc_id = TEST_CASE_MAP[test_name]
            update_helix_test_run_result(
                RUN_ID,
                tc_id,
                test_result["result"],
                test_result["message"]
            )
        else:
            print(f"WARNING: No Helix mapping for test '{test_name}' - skipping")
    
    print(f"Submitted {len(junit_results)} results to Helix Test Run {RUN_ID}")

Step 5: Mark the test run as complete once all results are submitted:

# Close the test run, setting its final status
curl -X PUT \
  "https://helix-server.example.com:8443/rest/api/v1/testruns/TR-5890" \
  -H "Authorization: Basic $(echo -n 'svc_test_integration:YourPassword' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "Completed",
    "conclusion": "Passed"
  }'

Workflow 2: Using tccli for Bulk Operations

For teams that prefer shell scripting over direct REST API calls, tccli provides a simplified interface. It's ideal for CI pipelines where curl + jq may be cumbersome:

#!/bin/bash
# ci_integration.sh - Complete CI integration script using tccli

set -euo pipefail

# --- Initialize tccli session ---
tccli login --profile ci-integration

# --- Create test run and capture its ID ---
RUN_ID=$(tccli testrun create \
  --name "Regression Suite - Build ${CI_BUILD_NUMBER} - $(date +%Y-%m-%d)" \
  --status "InProgress" \
  --filter "labels=regression" \
  --project "ProjectAlpha" \
  --output-format json | jq -r '.id')

echo "Created Helix Test Run: $RUN_ID"

# --- Execute tests ---
cd /app/tests
mvn test -Dtest="RegressionSuite" -DfailIfNoTests=false

# --- Submit results in batch ---
# tccli can parse JUnit XML directly and submit results
tccli testrun submit-results \
  --test-run-id "$RUN_ID" \
  --junit-file target/surefire-reports/TEST-RegressionSuite.xml \
  --mapping-file test_case_mapping.json \
  --profile ci-integration

# --- Complete the test run ---
tccli testrun update \
  --test-run-id "$RUN_ID" \
  --status "Completed" \
  --conclusion "Passed"

echo "Test run $RUN_ID completed successfully."

The mapping file test_case_mapping.json referenced above bridges framework test names to Helix test case IDs:

{
  "mappings": [
    {"junitName": "com.app.RegressionSuite.testOrderCreation", "helixTC": "TC-2001"},
    {"junitName": "com.app.RegressionSuite.testPaymentProcessing", "helixTC": "TC-2002"},
    {"junitName": "com.app.RegressionSuite.testInventoryUpdate", "helixTC": "TC-2003"},
    {"junitName": "com.app.RegressionSuite.testEmailNotification", "helixTC": "TC-2004"}
  ],
  "defaultVerdictOnMissingMapping": "ignore"
}

Workflow 3: Webhook-Driven Integration for Event-Based Triggers

Helix ALM supports webhooks that fire on test run state changes. You can invert the flow: let Helix trigger your CI pipeline when a test run is created manually, then have the pipeline execute tests and report back. This is useful for manual test run approval workflows.

First, configure a webhook in Helix ALM Admin UI or via API:

# Register a webhook that fires when a test run enters "Ready for Execution" status
curl -X POST \
  "https://helix-server.example.com:8443/rest/api/v1/webhooks" \
  -H "Authorization: Basic $(echo -n 'admin:password' | base64)" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI Trigger Webhook",
    "url": "https://jenkins.example.com/generic-webhook-trigger/invoke?token=helix-trigger",
    "events": ["testrun.status.changed"],
    "filter": "status=Ready for Execution",
    "active": true
  }'

On the CI side (Jenkins Pipeline example), receive the webhook payload and extract the test run ID:

// Jenkinsfile - Triggered by Helix webhook
pipeline {
    agent any
    
    triggers {
        // Generic webhook trigger plugin
        genericVariables([
            key: 'helix_run_id', 
            value: '$.payload.testrun.id'  // JSONPath to extract test run ID
        ])
    }
    
    stages {
        stage('Checkout') {
            steps {
                git url: 'https://github.com/example/project.git', branch: 'main'
            }
        }
        
        stage('Execute Tests') {
            steps {
                script {
                    // Fetch test cases associated with this Helix test run
                    def testCases = sh(
                        script: """
                            curl -s -X GET \
                              "https://helix-server.example.com:8443/rest/api/v1/testruns/${env.helix_run_id}/testcases" \
                              -u "svc_test_integration:${HELIX_PASS}" | jq -r '.data[].name'
                        """,
                        returnStdout: true
                    ).trim()
                    
                    echo "Executing Helix test cases: ${testCases}"
                    
                    // Run tests matching these test case names
                    sh """
                        pytest -k "${testCases.replace('\n', ' or ')}" --junitxml=results.xml
                    """
                }
            }
        }
        
        stage('Report Results') {
            steps {
                sh '''
                    python3 submit_results.py  # Same script from Workflow 1
                '''
            }
        }
    }
}

Workflow 4: Linking Source Code Changes to Test Results

One of Helix's most powerful features is the ability to link changelists (from Helix Core or Git) directly to test cases and test runs. This provides full bidirectional traceability: you can see which code changes were tested by which test run, and vice versa.

# Example: During CI, capture the changelist or commit SHA and link it to the test run
# For Helix Core (Perforce):
CHANGELIST=$(p4 changes -m 1 -t //depot/main/... | awk '{print $2}')
# For Git:
COMMIT_SHA=$(git rev-parse HEAD)

# Link the changelist to the test run in Helix
curl -X POST \
  "https://helix-server.example.com:8443/rest/api/v1/testruns/TR-5890/links" \
  -H "Authorization: Basic $(echo -n 'svc_test_integration:YourPassword' | base64)" \
  -H "Content-Type: application/json" \
  -d "{
    \"linkedItemType\": \"changelist\",
    \"linkedItemId\": \"${COMMIT_SHA}\",
    \"linkType\": \"TestedBy\",
    \"repository\": \"ProjectAlpha-GitHub\"
  }"

# You can also link individual test case results to specific changelists
# for granular traceability
curl -X POST \
  "https://helix-server.example.com:8443/rest/api/v1/testcases/TC-1001/links" \
  -H "Authorization: Basic $(echo -n 'svc_test_integration:YourPassword' | base64)" \
  -H "Content-Type: application/json" \
  -d "{
    \"linkedItemType\": \"changelist\",
    \"linkedItemId\": \"${COMMIT_SHA}\",
    \"linkType\": \"VerifiedBy\",
    \"repository\": \"ProjectAlpha-GitHub\"
  }"

Advanced Integration Patterns

Pattern 1: Parallel Test Execution with Aggregated Results

When your test suite is large and runs across multiple parallel CI nodes, you need to aggregate results into a single Helix test run. The approach is to create the test run upfront, distribute test case subsets to each parallel executor, and have each executor submit results independently:

#!/bin/bash
# master_aggregator.sh - Orchestrates parallel test execution and aggregation

# Step 1: Create the master test run
RUN_ID=$(tccli testrun create \
  --name "Full Regression - Build ${BUILD_NUMBER}" \
  --status "InProgress" \
  --filter "labels=regression" \
  --output-format json | jq -r '.id')

# Step 2: Fetch all test cases for this run and split into chunks
ALL_TEST_CASES=$(curl -s \
  "https://helix-server.example.com:8443/rest/api/v1/testruns/${RUN_ID}/testcases" \
  -u "${USER}:${PASS}" | jq -r '.data[].id')

# Split into 4 chunks for 4 parallel workers
echo "$ALL_TEST_CASES" | split -l $(($(echo "$ALL_TEST_CASES" | wc -l) / 4 + 1)) - chunk_

# Step 3: Dispatch to parallel workers (Jenkins parallel stages, GitHub matrix, etc.)
# Each worker receives its chunk file and the RUN_ID
for CHUNK_FILE in chunk_*; do
    # In a real CI setup, this would be a parallel job call
    # For demonstration, we'll use background processes
    (
        CHUNK_TC_IDS=$(cat "$CHUNK_FILE" | tr '\n' ',')
        # Execute only the tests mapped to these Helix TC IDs
        pytest --helix-tc-filter="${CHUNK_TC_IDS}" --junitxml="results_${CHUNK_FILE}.xml"
        
        # Submit results for this chunk
        tccli testrun submit-results \
          --test-run-id "$RUN_ID" \
          --junit-file "results_${CHUNK_FILE}.xml" \
          --mapping-file test_case_mapping.json
    ) &
done

# Wait for all parallel workers to finish
wait

# Step 4: Verify all test cases have results and close the run
PENDING_COUNT=$(tccli testrun get --test-run-id "$RUN_ID" --output-format json | \
  jq '.testCases | map(select(.verdict == "NotRun")) | length')

if [ "$PENDING_COUNT" -eq 0 ]; then
    tccli testrun update --test-run-id "$RUN_ID" --status "Completed" --conclusion "Passed"
else
    echo "WARNING: ${PENDING_COUNT} test cases still pending - run not closed"
fi

Pattern 2: Automated Flaky Test Detection

By accumulating historical test run data in Helix, you can build a flaky test detector. The following script queries the Helix REST API for recent test case results and flags any test that shows inconsistent pass/fail patterns:

#!/usr/bin/env python3
"""
flaky_detector.py - Identify flaky tests using Helix ALM historical data
"""

import requests
from collections import defaultdict

HELIX_SERVER = "https://helix-server.example.com:8443"
USER = "svc_test_integration"
PASS = "YourPassword"
DAYS_TO_ANALYZE = 14

def get_recent_results(days=14):
    """Fetch test case results from the last N days."""
    url = f"{HELIX_SERVER}/rest/api/v1/testruns/results"
    
    # Query for completed test run results in the date range
    params = {
        "filter": f"executionDate>now-{days}d",
        "fields": "testcaseId,verdict,testrunId",
        "limit": 5000
    }
    
    response = requests.get(url, auth=(USER, PASS), params=params)
    response.raise_for_status()
    return response.json().get("data", [])

def detect_flaky(results):
    """Analyze results per test case and identify flaky patterns."""
    tc_results = defaultdict(list)
    
    for result in results:
        tc_id = result["testcaseId"]
        verdict = result["verdict"]
        tc_results[tc_id].append(verdict)
    
    flaky_candidates = []
    
    for tc_id, verdicts in tc_results.items():
        # Need at least 5 runs to establish a pattern
        if len(verdicts) < 5:
            continue
        
        # Count transitions: passed->failed or failed->passed
        transitions = 0
        for i in range(1, len(verdicts)):
            if verdicts[i] != verdicts[i-1]:
                transitions += 1
        
        # If more than 20% of consecutive runs show different results, flag as flaky
        flakiness_ratio = transitions / (len(verdicts) - 1)
        if flakiness_ratio > 0.2:
            flaky_candidates.append({
                "testcaseId": tc_id,
                "flakinessRatio": round(flakiness_ratio, 2),
                "totalRuns": len(verdicts),
                "recentVerdicts": verdicts[-5:]
            })
    
    return sorted(flaky_candidates, key=lambda x: x["flakinessRatio"], reverse=True)

if __name__ == "__main__":
    print(f"Analyzing last {DAYS_TO_ANALYZE} days of Helix test results...")
    results = get_recent_results(DAYS_TO_ANALYZE)
    print(f"Retrieved {len(results)} individual test case results")
    
    flaky_tests = detect_flaky(results)
    
    if flaky_tests:
        print(f"\nFound {len(flaky_tests)} potentially flaky tests:")
        print("-" * 60)
        for test in flaky_tests[:10]:  # Top 10
            print(f"TC: {test['testcaseId']} | "
                  f"Flakiness: {test['flakinessRatio']} | "
                  f"Runs: {test['totalRuns']} | "
                  f"Recent: {test['recentVerdicts']}")
    else:
        print("No flaky tests detected in the analysis period.")

Pattern 3: Custom Dashboard and Metrics Export

Helix's REST API allows you to extract aggregate metrics for custom dashboards or integration with tools like Grafana, Power BI, or Splunk:

#!/usr/bin/env python3
"""
metrics_exporter.py - Export Helix test metrics to JSON for dashboard consumption
Outputs: test_pass_rate, requirements_coverage, open_defects, etc.
"""

import requests
import json
from datetime import datetime, timedelta

HELIX_SERVER = "https://helix-server.example.com:8443"
USER = "svc_test_integration"
PASS = "YourPassword"

def fetch_metrics():
    metrics = {}
    
    # 1. Test pass rate for the last 7 days
    resp = requests.get(
        f"{HELIX_SERVER}/rest/api/v1/testruns",
        params={
            "filter": "status=Completed and completionDate>now-7d",
            "fields": "id,conclusion"
        },
        auth=(USER, PASS)
    )
    runs = resp.json().get("data", [])
    passed = sum(1 for r in runs if r.get("conclusion") == "Passed")
    metrics["test_run_pass_rate_7d"] = round(passed / len(runs) * 100, 1) if runs else 0
    metrics["total_test_runs_7d"] = len(runs)
    
    # 2. Requirements coverage (requirements with linked test cases)
    resp = requests.get(
        f"{HELIX_SERVER}/rest/api/v1/requirements",
        params={
            "filter": "status=Approved",
            "fields": "id,linkedTestCasesCount"
        },
        auth=(USER, PASS)
    )
    reqs = resp.json().get("data", [])
    total_reqs = len(reqs)
    covered_reqs = sum(1 for r in reqs if r.get("linkedTestCasesCount", 0) > 0)
    metrics["requirements_coverage_pct"] = round(covered_reqs / total_reqs * 100, 1) if total_reqs else 0
    
    # 3. Open defects by severity
    resp = requests.get(
        f"{HELIX_SERVER}/rest/api/v1/issues",
        params={
            "filter": "status=Open",
            "fields": "id,severity"
        },
        auth=(USER, PASS)
    )
    issues = resp.json().get("data", [])
    severity_counts = {}
    for issue in issues:
        sev = issue.get("severity", "Unknown")
        severity_counts[sev] = severity_counts.get(sev, 0) + 1
    metrics["open_defects_by_severity"] = severity_counts
    metrics["total_open_defects"] = len(issues)
    
    # 4. Average test execution time
    resp = requests.get(
        f"{HELIX_SERVER}/rest/api/v1/testruns/results",
        params={
            "filter": "executionDate>now-7d",
            "fields": "executionTime",
            "limit": 10000
        },
        auth=(USER, PASS)
    )
    results = resp.json().get("data", [])
    times = [r.get("executionTime", 0) for r in results if r.get("executionTime")]
    metrics["avg_execution_time_seconds"] = round(sum(times) / len(times), 2) if times else 0
    
    return metrics

if __name__ == "__main__":
    metrics = fetch_metrics()
    timestamp = datetime.utcnow().isoformat() + "Z"
    
    output = {
        "timestamp": timestamp,
        "source": "Helix ALM Metrics Exporter",
        "metrics": metrics
    }
    
    print(json.dumps(output, indent=2))
    
    # Optionally write to a file for Grafana's JSON datasource or push to InfluxDB
    with open("/var/metrics/helix_metrics.json", "w") as f:
        json.dump(output, f, indent=2)

Best Practices for Helix Testing Integration

1. Establish a Consistent Test Case Naming Convention

Your automated tests in code must map reliably to Helix test cases. Adopt a convention that makes mapping deterministic. For example, annotate each test method with its Helix test case ID:

# Python / pytest example using custom markers
import pytest

@pytest.mark.helix_tc("TC-1001")
def test_login_success():
    assert login("user@example.com", "valid_password") is True

@pytest.mark.helix_tc("TC-1002")
def test_login_failure_wrong_password():
    assert login("user@example.com", "wrong_password") is False

# Then in your conftest.py, extract the marker for result submission:
# helix_tc_id = item.get_closest_marker('helix_tc').args[0]
// Java / JUnit 5 example using custom annotations
import org.junit.jupiter.api.Test;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface HelixTestCase {
    String value();
}

public class LoginTests {
    @Test
    @HelixTestCase("TC-1001")
    void testLoginSuccess() {
        assertTrue(LoginService.authenticate("user@example.com", "valid_password"));
    }
    
    @Test
    @HelixTestCase("TC-1002")
    void testLoginFailureWrongPassword() {
        assertFalse(LoginService.authenticate("user@example.com", "wrong_password"));
    }
}

2. Use Service Accounts with Minimal Permissions

Create

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles