Files
Atomizer/atomizer-field/test_suite.py

403 lines
11 KiB
Python
Raw Normal View History

"""
test_suite.py
Master test orchestrator for AtomizerField
AtomizerField Testing Framework v1.0
Comprehensive validation from basic functionality to full neural FEA predictions.
Usage:
python test_suite.py --quick # 5-minute smoke tests
python test_suite.py --physics # Physics validation tests
python test_suite.py --learning # Learning capability tests
python test_suite.py --full # Complete test suite (1 hour)
Testing Strategy:
1. Smoke Tests (5 min) Verify basic functionality
2. Physics Tests (15 min) Validate physics constraints
3. Learning Tests (30 min) Confirm learning capability
4. Integration Tests (1 hour) Full system validation
"""
import sys
import os
import argparse
import time
from pathlib import Path
import json
from datetime import datetime
# Add project root to path
sys.path.insert(0, str(Path(__file__).parent))
# Test results storage
TEST_RESULTS = {
'timestamp': datetime.now().isoformat(),
'tests': [],
'summary': {
'total': 0,
'passed': 0,
'failed': 0,
'skipped': 0
}
}
class TestRunner:
"""
Test orchestrator that runs all tests in sequence
"""
def __init__(self, mode='quick'):
"""
Initialize test runner
Args:
mode (str): Testing mode ('quick', 'physics', 'learning', 'full')
"""
self.mode = mode
self.results_dir = Path('test_results')
self.results_dir.mkdir(exist_ok=True)
print(f"\n{'='*60}")
print(f"AtomizerField Test Suite v1.0")
print(f"Mode: {mode.upper()}")
print(f"{'='*60}\n")
def run_test(self, test_name, test_func, description):
"""
Run a single test and record results
Args:
test_name (str): Name of test
test_func (callable): Test function to run
description (str): Test description
Returns:
bool: True if passed
"""
print(f"[TEST] {test_name}")
print(f" Description: {description}")
start_time = time.time()
result = {
'name': test_name,
'description': description,
'status': 'unknown',
'duration': 0,
'message': '',
'metrics': {}
}
try:
test_result = test_func()
if test_result is None or test_result is True:
result['status'] = 'PASS'
result['message'] = 'Test passed successfully'
print(f" Status: [PASS]")
TEST_RESULTS['summary']['passed'] += 1
elif isinstance(test_result, dict):
result['status'] = test_result.get('status', 'PASS')
result['message'] = test_result.get('message', '')
result['metrics'] = test_result.get('metrics', {})
if result['status'] == 'PASS':
print(f" Status: [PASS]")
TEST_RESULTS['summary']['passed'] += 1
else:
print(f" Status: [FAIL]")
print(f" Reason: {result['message']}")
TEST_RESULTS['summary']['failed'] += 1
else:
result['status'] = 'FAIL'
result['message'] = str(test_result)
print(f" Status: [FAIL]")
TEST_RESULTS['summary']['failed'] += 1
except Exception as e:
result['status'] = 'FAIL'
result['message'] = f"Exception: {str(e)}"
print(f" Status: [FAIL]")
print(f" Error: {str(e)}")
TEST_RESULTS['summary']['failed'] += 1
result['duration'] = time.time() - start_time
print(f" Duration: {result['duration']:.2f}s\n")
TEST_RESULTS['tests'].append(result)
TEST_RESULTS['summary']['total'] += 1
return result['status'] == 'PASS'
def run_smoke_tests(self):
"""
Quick smoke tests (5 minutes)
Verify basic functionality
"""
print(f"\n{'='*60}")
print("PHASE 1: SMOKE TESTS (5 minutes)")
print(f"{'='*60}\n")
from tests import test_synthetic
# Test 1: Model creation
self.run_test(
"Model Creation",
test_synthetic.test_model_creation,
"Verify GNN model can be instantiated"
)
# Test 2: Forward pass
self.run_test(
"Forward Pass",
test_synthetic.test_forward_pass,
"Verify model can process dummy data"
)
# Test 3: Loss computation
self.run_test(
"Loss Computation",
test_synthetic.test_loss_computation,
"Verify loss functions work"
)
def run_physics_tests(self):
"""
Physics validation tests (15 minutes)
Ensure physics constraints work
"""
print(f"\n{'='*60}")
print("PHASE 2: PHYSICS VALIDATION (15 minutes)")
print(f"{'='*60}\n")
from tests import test_physics
# Test 1: Cantilever beam
self.run_test(
"Cantilever Beam (Analytical)",
test_physics.test_cantilever_analytical,
"Compare with δ = FL³/3EI solution"
)
# Test 2: Equilibrium
self.run_test(
"Equilibrium Check",
test_physics.test_equilibrium,
"Verify force balance (∇·σ + f = 0)"
)
# Test 3: Energy conservation
self.run_test(
"Energy Conservation",
test_physics.test_energy_conservation,
"Verify strain energy = work done"
)
def run_learning_tests(self):
"""
Learning capability tests (30 minutes)
Confirm network can learn
"""
print(f"\n{'='*60}")
print("PHASE 3: LEARNING CAPABILITY (30 minutes)")
print(f"{'='*60}\n")
from tests import test_learning
# Test 1: Memorization
self.run_test(
"Memorization Test",
test_learning.test_memorization,
"Can network memorize small dataset?"
)
# Test 2: Interpolation
self.run_test(
"Interpolation Test",
test_learning.test_interpolation,
"Can network interpolate between training points?"
)
# Test 3: Pattern recognition
self.run_test(
"Pattern Recognition",
test_learning.test_pattern_recognition,
"Does network learn thickness → stress relationship?"
)
def run_integration_tests(self):
"""
Full integration tests (1 hour)
Complete system validation
"""
print(f"\n{'='*60}")
print("PHASE 4: INTEGRATION TESTS (1 hour)")
print(f"{'='*60}\n")
from tests import test_predictions
# Test 1: Parser validation
self.run_test(
"Parser Validation",
test_predictions.test_parser,
"Verify data parsing works correctly"
)
# Test 2: Training pipeline
self.run_test(
"Training Pipeline",
test_predictions.test_training,
"Verify complete training workflow"
)
# Test 3: Prediction accuracy
self.run_test(
"Prediction Accuracy",
test_predictions.test_prediction_accuracy,
"Compare neural vs FEA predictions"
)
def print_summary(self):
"""Print test summary"""
summary = TEST_RESULTS['summary']
print(f"\n{'='*60}")
print("TEST SUMMARY")
print(f"{'='*60}\n")
total = summary['total']
passed = summary['passed']
failed = summary['failed']
pass_rate = (passed / total * 100) if total > 0 else 0
print(f"Total Tests: {total}")
print(f" + Passed: {passed}")
print(f" - Failed: {failed}")
print(f" Pass Rate: {pass_rate:.1f}%\n")
if failed == 0:
print("[SUCCESS] ALL TESTS PASSED - SYSTEM READY!")
else:
print(f"[ERROR] {failed} TEST(S) FAILED - REVIEW REQUIRED")
print(f"\n{'='*60}\n")
def save_results(self):
"""Save test results to JSON"""
results_file = self.results_dir / f'test_results_{self.mode}_{int(time.time())}.json'
with open(results_file, 'w') as f:
json.dump(TEST_RESULTS, f, indent=2)
print(f"Results saved to: {results_file}")
def run(self):
"""
Run test suite based on mode
"""
start_time = time.time()
if self.mode == 'quick':
self.run_smoke_tests()
elif self.mode == 'physics':
self.run_smoke_tests()
self.run_physics_tests()
elif self.mode == 'learning':
self.run_smoke_tests()
self.run_physics_tests()
self.run_learning_tests()
elif self.mode == 'full':
self.run_smoke_tests()
self.run_physics_tests()
self.run_learning_tests()
self.run_integration_tests()
total_time = time.time() - start_time
# Print summary
self.print_summary()
print(f"Total testing time: {total_time/60:.1f} minutes\n")
# Save results
self.save_results()
# Return exit code
return 0 if TEST_RESULTS['summary']['failed'] == 0 else 1
def main():
"""Main entry point"""
parser = argparse.ArgumentParser(
description='AtomizerField Test Suite',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
# Quick smoke tests (5 min)
python test_suite.py --quick
# Physics validation (15 min)
python test_suite.py --physics
# Learning tests (30 min)
python test_suite.py --learning
# Full test suite (1 hour)
python test_suite.py --full
"""
)
parser.add_argument(
'--quick',
action='store_true',
help='Run quick smoke tests (5 minutes)'
)
parser.add_argument(
'--physics',
action='store_true',
help='Run physics validation tests (15 minutes)'
)
parser.add_argument(
'--learning',
action='store_true',
help='Run learning capability tests (30 minutes)'
)
parser.add_argument(
'--full',
action='store_true',
help='Run complete test suite (1 hour)'
)
args = parser.parse_args()
# Determine mode
if args.full:
mode = 'full'
elif args.learning:
mode = 'learning'
elif args.physics:
mode = 'physics'
elif args.quick:
mode = 'quick'
else:
# Default to quick if no mode specified
mode = 'quick'
print("No mode specified, defaulting to --quick")
# Run tests
runner = TestRunner(mode=mode)
exit_code = runner.run()
sys.exit(exit_code)
if __name__ == "__main__":
main()