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}") # Register the plugin @pytest.hookimpl(trylast=True) def pytest_configure(config): """Register the JSON reporter plugin.""" config._json_reporter = JSONReporter(config) config.pluginmanager.register(config._json_reporter, "json_reporter")