Skip to content

Commit 6f3f60b

Browse files
committed
Improve test runner output and add timing info
Enhanced the BrainPy minimal test runner with clearer output formatting, timing for each test group, and summary statistics. Now displays pass/fail status with durations, extracts recent failures for easier debugging, and provides a concise summary of test results.
1 parent 7667050 commit 6f3f60b

1 file changed

Lines changed: 70 additions & 26 deletions

File tree

pytest_groups.py

Lines changed: 70 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import subprocess
77
import sys
88
import os
9+
import time
910

1011
# Only the specific tests that cause state pollution issues
1112
ISOLATED_TESTS = [
@@ -42,14 +43,14 @@ def run_isolated_test(test_path):
4243

4344
def main():
4445
"""Run tests with minimal isolation - only isolate known problematic tests."""
45-
print("Starting minimal isolated test runner for BrainPy...")
46+
start_time = time.time()
4647

4748
# GitHub Actions specific settings
4849
is_github_actions = os.getenv('IS_GITHUB_ACTIONS') == '1'
4950
base_cmd = [sys.executable, "-m", "pytest"]
5051
test_args = ["-v", "--tb=short"]
5152
if is_github_actions:
52-
test_args.extend(["--maxfail=5", "-q"])
53+
test_args.extend(["--maxfail=5"])
5354

5455
# Build ignore list - only ignore files that contain problematic tests
5556
ignore_patterns = []
@@ -64,47 +65,90 @@ def main():
6465
for file_path in all_problematic_files:
6566
ignore_patterns.append(f"--ignore={file_path}")
6667

68+
print("=" * 80)
69+
print("BrainPy Test Suite (with state pollution isolation)")
70+
print("=" * 80)
71+
6772
# Run main test suite (excluding problematic files)
68-
print("\n" + "="*60)
69-
print("RUNNING MAIN TEST SUITE (excluding problematic files)")
70-
print("="*60)
73+
print(f"\n{'🔄 Running main test suite...':<60} ", end="", flush=True)
7174

7275
cmd = base_cmd + ["brainpy/_src/"] + test_args + ignore_patterns
73-
main_result = subprocess.run(cmd)
76+
main_start = time.time()
77+
main_result = subprocess.run(cmd, capture_output=True, text=True)
78+
main_time = time.time() - main_start
7479
main_passed = main_result.returncode == 0
7580

76-
# Run isolated problematic files
77-
print("\n" + "="*60)
78-
print("RUNNING ISOLATED PROBLEMATIC FILES")
79-
print("="*60)
81+
if main_passed:
82+
print(f"✅ PASSED ({main_time:.1f}s)")
83+
else:
84+
print(f"❌ FAILED ({main_time:.1f}s)")
85+
if not is_github_actions:
86+
# Extract key info from pytest output
87+
lines = main_result.stdout.split('\n')
88+
failed_lines = [line for line in lines if 'FAILED' in line][:5] # Show first 5 failures
89+
if failed_lines:
90+
print("\n Recent failures:")
91+
for line in failed_lines:
92+
print(f" {line}")
8093

94+
# Run isolated problematic files
8195
isolated_results = []
8296
for file_path in sorted(all_problematic_files):
8397
if os.path.exists(file_path):
84-
print(f"Running isolated file: {file_path}")
98+
file_name = file_path.split("/")[-1]
99+
print(f"{'🔄 Isolated: ' + file_name:<60} ", end="", flush=True)
100+
85101
cmd = base_cmd + [file_path] + test_args + ["-x"]
86-
result = subprocess.run(cmd)
87-
isolated_results.append(result.returncode == 0)
102+
iso_start = time.time()
103+
result = subprocess.run(cmd, capture_output=True, text=True)
104+
iso_time = time.time() - iso_start
105+
passed = result.returncode == 0
106+
isolated_results.append(passed)
107+
108+
if passed:
109+
print(f"✅ PASSED ({iso_time:.1f}s)")
110+
else:
111+
print(f"❌ FAILED ({iso_time:.1f}s)")
112+
if not is_github_actions:
113+
lines = result.stdout.split('\n')
114+
failed_lines = [line for line in lines if 'FAILED' in line][:3]
115+
if failed_lines:
116+
print(" Failures:")
117+
for line in failed_lines:
118+
print(f" {line}")
88119
else:
89-
print(f"Skipping non-existent file: {file_path}")
90120
isolated_results.append(True)
91121

92-
# Summary
93-
print("\n" + "="*60)
94-
print("TEST SUMMARY")
95-
print("="*60)
122+
# Final summary in pytest style
123+
total_time = time.time() - start_time
124+
print("\n" + "=" * 80)
96125

97126
all_passed = main_passed and all(isolated_results)
127+
total_groups = 1 + len([f for f in all_problematic_files if os.path.exists(f)])
128+
passed_groups = (1 if main_passed else 0) + sum(isolated_results)
129+
failed_groups = total_groups - passed_groups
98130

99-
print(f"Main test suite: {'✓ PASSED' if main_passed else '✗ FAILED'}")
100-
print(f"Isolated files: {'✓ PASSED' if all(isolated_results) else '✗ FAILED'} ({len([r for r in isolated_results if r])}/{len(isolated_results)})")
101-
102-
if not all_passed:
103-
print("\nSome tests failed. Re-run individually to debug.")
104-
return 1
131+
if all_passed:
132+
print(f"{'=' * 25}{passed_groups} passed in {total_time:.1f}s {'=' * 25}")
105133
else:
106-
print("\nAll tests passed!")
107-
return 0
134+
status_parts = []
135+
if failed_groups > 0:
136+
status_parts.append(f"❌ {failed_groups} failed")
137+
if passed_groups > 0:
138+
status_parts.append(f"✅ {passed_groups} passed")
139+
140+
status = ", ".join(status_parts)
141+
print(f"{'=' * 20} {status} in {total_time:.1f}s {'=' * 20}")
142+
143+
if not all_passed:
144+
print("\nFailed test groups:")
145+
if not main_passed:
146+
print(" • Main test suite")
147+
for file_path, passed in zip(sorted(all_problematic_files), isolated_results):
148+
if os.path.exists(file_path) and not passed:
149+
print(f" • {file_path}")
150+
151+
return 0 if all_passed else 1
108152

109153
if __name__ == "__main__":
110154
exit_code = main()

0 commit comments

Comments
 (0)