Skip to main content
Learn how to set up automated testing with Hopx Sandboxes to run tests in isolated environments with clean state every time.

Overview

This tutorial shows you how to:
  • Run unit tests in isolated sandboxes
  • Execute integration tests with dependencies
  • Run tests in parallel
  • Generate test reports
  • Clean up resources automatically

Prerequisites

  • Python SDK installed (pip install hopx-ai)
  • API key configured (see Authentication)
  • Basic understanding of testing frameworks (pytest, unittest, etc.)

Step 1: Basic Test Execution

Run tests in an isolated sandbox:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox

def run_tests(test_code: str):
    """Run tests in an isolated sandbox"""
    with Sandbox.create(template="code-interpreter") as sandbox:
        # Upload test file
        sandbox.files.write("/workspace/test_example.py", test_code)
        
        # Install pytest
        sandbox.commands.run("pip install pytest --quiet")
        
        # Run tests
        result = sandbox.commands.run("pytest /workspace/test_example.py -v")
        
        return {
            "success": result.success,
            "stdout": result.stdout,
            "stderr": result.stderr,
            "exit_code": result.exit_code
        }

# Example test code
test_code = """
def test_addition():
    assert 1 + 1 == 2

def test_subtraction():
    assert 5 - 3 == 2

def test_multiplication():
    assert 2 * 3 == 6
"""

results = run_tests(test_code)
print(results["stdout"])

Step 2: Test with Dependencies

Run tests that require external dependencies:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox

def run_tests_with_dependencies(test_code: str, requirements: str):
    """Run tests with dependencies"""
    with Sandbox.create(template="code-interpreter") as sandbox:
        # Upload requirements
        sandbox.files.write("/workspace/requirements.txt", requirements)
        
        # Install dependencies
        sandbox.commands.run("pip install -r /workspace/requirements.txt --quiet")
        
        # Upload test file
        sandbox.files.write("/workspace/test_example.py", test_code)
        
        # Run tests with coverage
        result = sandbox.commands.run("""
pip install pytest-cov --quiet && \
pytest /workspace/test_example.py -v --cov=. --cov-report=json
        """)
        
        # Download coverage report
        try:
            coverage = sandbox.files.read("/workspace/coverage.json")
            return {
                "success": result.success,
                "stdout": result.stdout,
                "coverage": coverage
            }
        except:
            return {
                "success": result.success,
                "stdout": result.stdout
            }

# Example with dependencies
requirements = """
requests==2.31.0
pytest==7.4.0
"""

test_code = """
import requests

def test_api_call():
    response = requests.get("https://jsonplaceholder.typicode.com/posts/1")
    assert response.status_code == 200
    assert "id" in response.json()
"""

results = run_tests_with_dependencies(test_code, requirements)
print(results["stdout"])

Step 3: Parallel Test Execution

Run multiple test suites in parallel:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox
import concurrent.futures
from typing import List, Dict

def run_tests_parallel(test_suites: List[Dict[str, str]]) -> List[Dict]:
    """Run multiple test suites in parallel"""
    def run_single_suite(suite: Dict[str, str]) -> Dict:
        with Sandbox.create(template="code-interpreter") as sandbox:
            # Upload test file
            sandbox.files.write("/workspace/test.py", suite["code"])
            
            # Install dependencies if provided
            if "requirements" in suite:
                sandbox.files.write("/workspace/requirements.txt", suite["requirements"])
                sandbox.commands.run("pip install -r /workspace/requirements.txt --quiet")
            
            # Run tests
            result = sandbox.commands.run("pytest /workspace/test.py -v --json-report --json-report-file=/workspace/report.json")
            
            # Download report
            try:
                report = sandbox.files.read("/workspace/report.json")
                return {
                    "suite": suite.get("name", "unknown"),
                    "success": result.success,
                    "stdout": result.stdout,
                    "report": report
                }
            except:
                return {
                    "suite": suite.get("name", "unknown"),
                    "success": result.success,
                    "stdout": result.stdout
                }
    
    # Run all suites in parallel
    with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
        results = list(executor.map(run_single_suite, test_suites))
    
    return results

# Example: Run multiple test suites
test_suites = [
    {
        "name": "unit_tests",
        "code": """
def test_add():
    assert 1 + 1 == 2
def test_multiply():
    assert 2 * 3 == 6
        """
    },
    {
        "name": "integration_tests",
        "code": """
import requests
def test_api():
    r = requests.get("https://jsonplaceholder.typicode.com/posts/1")
    assert r.status_code == 200
        """,
        "requirements": "requests==2.31.0\npytest==7.4.0"
    }
]

results = run_tests_parallel(test_suites)
for result in results:
    print(f"{result['suite']}: {'✅' if result['success'] else '❌'}")

Step 4: Complete Testing Framework

Build a complete testing framework:
  • Python
  • JavaScript/TypeScript
from hopx_ai import Sandbox
from typing import List, Dict, Optional
import json
import time

class TestRunner:
    """Complete testing framework"""
    
    def __init__(self, template: str = "code-interpreter"):
        self.template = template
    
    def run_test_suite(
        self,
        test_code: str,
        requirements: Optional[str] = None,
        timeout: int = 300
    ) -> Dict:
        """Run a complete test suite"""
        with Sandbox.create(template=self.template) as sandbox:
            start_time = time.time()
            
            # Setup
            sandbox.files.write("/workspace/test.py", test_code)
            
            if requirements:
                sandbox.files.write("/workspace/requirements.txt", requirements)
                install_result = sandbox.commands.run(
                    "pip install -r /workspace/requirements.txt --quiet",
                    timeout=120
                )
                if not install_result.success:
                    return {
                        "success": False,
                        "error": "Dependency installation failed",
                        "stderr": install_result.stderr
                    }
            
            # Run tests
            test_result = sandbox.commands.run(
                "pytest /workspace/test.py -v --tb=short --json-report --json-report-file=/workspace/report.json",
                timeout=timeout
            )
            
            # Get report
            try:
                report_json = sandbox.files.read("/workspace/report.json")
                report = json.loads(report_json)
            except:
                report = None
            
            elapsed = time.time() - start_time
            
            return {
                "success": test_result.success,
                "stdout": test_result.stdout,
                "stderr": test_result.stderr,
                "exit_code": test_result.exit_code,
                "duration": elapsed,
                "report": report
            }
    
    def run_multiple_suites(
        self,
        suites: List[Dict[str, str]],
        max_parallel: int = 5
    ) -> List[Dict]:
        """Run multiple test suites"""
        from concurrent.futures import ThreadPoolExecutor
        
        def run_suite(suite: Dict) -> Dict:
            result = self.run_test_suite(
                suite["code"],
                suite.get("requirements"),
                suite.get("timeout", 300)
            )
            result["suite_name"] = suite.get("name", "unknown")
            return result
        
        with ThreadPoolExecutor(max_workers=max_parallel) as executor:
            results = list(executor.map(run_suite, suites))
        
        return results

# Usage
runner = TestRunner()

result = runner.run_test_suite("""
def test_example():
    assert True
""")

print(f"Tests {'passed' if result['success'] else 'failed'}")
print(f"Duration: {result['duration']:.2f}s")

Best Practices

Each test suite should run in its own sandbox for complete isolation:
# ✅ Good: Isolated sandbox per test
with Sandbox.create(...) as sandbox:
    run_tests(sandbox)

# ❌ Bad: Reusing sandbox
# sandbox = Sandbox.create(...)
# run_test1(sandbox)  # State may leak
# run_test2(sandbox)  # Contaminated state
Always set reasonable timeouts to prevent hanging tests:
result = sandbox.commands.run("pytest test.py", timeout=300)  # 5 minutes
Generate test reports for CI/CD integration:
sandbox.commands.run("pytest test.py --json-report --json-report-file=report.json")
report = sandbox.files.read("report.json")
Always clean up sandboxes after tests complete:
# Use context manager for automatic cleanup
with Sandbox.create(...) as sandbox:
    run_tests(sandbox)
# Sandbox automatically deleted

Next Steps