Arch/tests/json_reporter.py

102 lines
3.7 KiB
Python

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')