import json import pytest import datetime import os import time from pathlib import Path class JSONReporter: """ Custom pytest plugin to generate JSON test reports. Based on the specification in section 9.4 of descripcion.md. """ def __init__(self, config): self.config = config self.start_time = time.time() self.results = { 'summary': { 'total': 0, 'passed': 0, 'failed': 0, 'skipped': 0, 'error': 0, 'duration': 0, 'timestamp': datetime.datetime.now().isoformat() }, 'tests': [] } def pytest_runtest_logreport(self, report): """Handle the reporting of a test run.""" if report.when == 'call' or (report.when == 'setup' and report.skipped): self.results['summary']['total'] += 1 if report.passed: result = 'passed' self.results['summary']['passed'] += 1 elif report.failed: if report.when != 'call': result = 'error' self.results['summary']['error'] += 1 else: result = 'failed' self.results['summary']['failed'] += 1 elif report.skipped: result = 'skipped' self.results['summary']['skipped'] += 1 # Extract test metadata test_module = report.nodeid.split('::')[0] test_class = report.nodeid.split('::')[1] if '::' in report.nodeid else None test_name = report.nodeid.split('::')[-1] # Extract error details if present error_message = None error_trace = None if hasattr(report, 'longrepr') and report.longrepr: if hasattr(report.longrepr, 'reprcrash') and report.longrepr.reprcrash: error_message = report.longrepr.reprcrash.message error_trace = str(report.longrepr) # Add test result to list self.results['tests'].append({ 'id': report.nodeid, 'module': test_module, 'class': test_class, 'name': test_name, 'result': result, 'duration': report.duration, 'error_message': error_message, 'error_trace': error_trace }) def pytest_sessionfinish(self, session): """Generate report at end of test session.""" self.results['summary']['duration'] = time.time() - self.start_time # Create output directory if it doesn't exist output_dir = Path('test_reports') output_dir.mkdir(exist_ok=True) # Generate timestamp for file name timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S') output_path = output_dir / f'test_results_{timestamp}.json' # Write results to file with open(output_path, 'w', encoding='utf-8') as f: json.dump(self.results, f, indent=2, ensure_ascii=False) # Also create a symlink/copy to latest results latest_path = output_dir / 'test_results_latest.json' if os.path.exists(latest_path): os.remove(latest_path) with open(latest_path, 'w', encoding='utf-8') as f: json.dump(self.results, f, indent=2, ensure_ascii=False) print(f"\nJSON test report generated: {output_path}") @pytest.hookimpl(tryfirst=True) def pytest_configure(config): """Register the JSON reporter plugin.""" config.pluginmanager.register(JSONReporter(config), 'json_reporter')