# Testing Showcase: Professional Robotics Without Hardware This project demonstrates **industry-standard testing practices** for robotics code. ## The Revolutionary Idea **You can test robot logic without a robot!** Traditional FTC: - Write code - Deploy to robot (5+ minutes) - Test on robot - Find bug - Repeat... With proper testing: - Write code - Run tests (2 seconds) - Fix bugs instantly - Deploy confident code to robot ## Test Categories in This Project ### 1. Unit Tests (Component-Level) Test individual behaviors in isolation. **Example: Motor Power Levels** ```java @Test void testFullSpeedWhenFar() { sensor.setDistance(100.0); // Far from wall wallApproach.start(); wallApproach.update(); assertEquals(0.6, motor.getPower(), 0.001, // Full speed "Should drive at full speed when far"); } ``` **What this tests:** - Speed control logic - Distance threshold detection - Motor power calculation **Time to run:** ~5 milliseconds ### 2. System Tests (Complete Scenarios) Test entire sequences working together. **Example: Complete Autonomous Mission** ```java @Test void testCompleteAutonomousMission() { // Phase 1: Drive 100cm to wall distanceSensor.setDistance(100.0); wallApproach.start(); while (wallApproach.getState() != STOPPED) { wallApproach.update(); distanceSensor.approach(motor.getPower() * 2.0); } // Phase 2: Turn 90° right turnController.turnTo(90); while (turnController.getState() == TURNING) { turnController.update(); gyro.rotate(motor.getPower() * 2.0); } // Verify complete mission success assertEquals(STOPPED, wallApproach.getState()); assertEquals(90, gyro.getHeading(), 2.0); } ``` **What this tests:** - Multiple subsystems coordinating - State transitions between phases - Sensor data flowing correctly - Complete mission execution **Time to run:** ~50 milliseconds ### 3. Edge Case Tests (Failure Modes) Test things that are hard/dangerous to test on a real robot. **Example: Sensor Failure** ```java @Test void testSensorFailureHandling() { wallApproach.start(); // Sensor suddenly disconnects! sensor.simulateFailure(); wallApproach.update(); // Robot should safely stop assertEquals(ERROR, wallApproach.getState()); assertEquals(0.0, motor.getPower()); assertTrue(wallApproach.hasSensorError()); } ``` **What this tests:** - Error detection - Safe shutdown procedures - Graceful degradation - Diagnostic reporting **Time to run:** ~2 milliseconds **Why this matters:** - Can't safely disconnect sensors on real robot during testing - Would risk crashing robot into wall - Tests this scenario hundreds of times instantly ### 4. Integration Tests (System-Level) Test multiple subsystems interacting realistically. **Example: Square Pattern Navigation** ```java @Test void testSquarePattern() { for (int side = 1; side <= 4; side++) { // Drive forward to wall distanceSensor.setDistance(50.0); wallApproach.start(); simulateDriving(); // Turn 90° right turnController.turnTo(side * 90); simulateTurning(); } // Should complete square and face original direction assertTrue(Math.abs(gyro.getHeading()) <= 2.0); } ``` **What this tests:** - Sequential operations - Repeated patterns - Accumulated errors - Return to starting position **Time to run:** ~200 milliseconds ## Real-World Scenarios You Can Test ### Scenario 1: Approaching Moving Target ```java @Test void testApproachingMovingTarget() { distanceSensor.setDistance(100.0); wallApproach.start(); for (int i = 0; i < 50; i++) { wallApproach.update(); // Target is also moving away! distanceSensor.approach(motor.getPower() * 2.0 - 0.5); // Robot should still eventually catch up } assertTrue(distanceSensor.getDistanceCm() < 15.0); } ``` ### Scenario 2: Noisy Sensor Data ```java @Test void testHandlesNoisySensors() { sensor.setNoise(2.0); // ±2cm random jitter sensor.setDistance(50.0); wallApproach.start(); // Run 100 updates with noisy data for (int i = 0; i < 100; i++) { wallApproach.update(); sensor.approach(0.5); // Should not oscillate wildly or crash assertTrue(motor.getPower() >= 0); assertTrue(motor.getPower() <= 1.0); } } ``` ### Scenario 3: Gyro Drift Compensation ```java @Test void testCompensatesForGyroDrift() { gyro.setHeading(0); gyro.setDrift(0.5); // 0.5° per second drift turnController.turnTo(90); // Simulate turn with drift for (int i = 0; i < 100; i++) { turnController.update(); gyro.rotate(motor.getPower() * 2.0); Thread.sleep(10); // Let drift accumulate } // Should still reach target despite drift assertTrue(Math.abs(gyro.getHeading() - 90) <= 2.0); } ``` ### Scenario 4: Battery Voltage Drop ```java @Test void testLowBatteryCompensation() { MockBattery battery = new MockBattery(); MotorController motor = new VoltageCompensatedMotor(battery); // Full battery battery.setVoltage(12.5); motor.setPower(0.5); assertEquals(0.5, motor.getActualPower()); // Low battery battery.setVoltage(11.0); motor.setPower(0.5); assertTrue(motor.getActualPower() > 0.5, // Compensated up "Should increase power to compensate for voltage drop"); } ``` ## Testing Benefits ### Speed - **41 tests run in < 2 seconds** - No deployment time - No robot setup time - Instant feedback ### Reliability - Test edge cases safely - Test failure modes - Test thousands of scenarios - Catch bugs before robot time ### Confidence - Know code works before deploying - Automated regression testing - Safe refactoring - Professional quality ### Learning - Students learn professional practices - Industry-standard patterns - Test-driven development - Debugging without hardware ## Test Metrics ``` Total Tests: 41 - MotorCyclerTest: 8 tests - WallApproachTest: 13 tests - TurnControllerTest: 15 tests - AutonomousIntegrationTest: 5 tests Total Runtime: < 2 seconds Lines of Test Code: ~1,200 Lines of Production Code: ~500 Test Coverage: Excellent Bugs Caught Before Robot Testing: Countless! ``` ## The Pattern for Students Teaching students this approach gives them: 1. **Immediate feedback** - No waiting for robot 2. **Safe experimentation** - Can't break robot in tests 3. **Professional skills** - Industry-standard practices 4. **Better code** - Testable code is well-designed code 5. **Confidence** - Know it works before deploying ## Comparison ### Traditional FTC Development ``` Write code (10 min) ↓ Deploy to robot (5 min) ↓ Test on robot (10 min) ↓ Find bug ↓ Repeat... Time per iteration: ~25 minutes Bugs found: Late (on robot) Risk: High (can damage robot) ``` ### With Testing ``` Write code (10 min) ↓ Run tests (2 sec) ↓ Fix bugs immediately (5 min) ↓ Deploy confident code (5 min) ↓ Works on robot! Time per iteration: ~20 minutes (first deploy!) Bugs found: Early (in tests) Risk: Low (robot rarely crashes) ``` ## Advanced Testing Patterns ### Parameterized Tests Test the same logic with different inputs: ```java @ParameterizedTest @ValueSource(doubles = {10, 20, 30, 40, 50}) void testDifferentStopDistances(double distance) { sensor.setDistance(100.0); wallApproach = new WallApproach(sensor, motor, distance); wallApproach.start(); simulateDriving(); assertTrue(sensor.getDistanceCm() <= distance + 2); } ``` ### State Machine Verification Test all state transitions: ```java @Test void testAllStateTransitions() { // INIT → APPROACHING wallApproach.start(); assertEquals(APPROACHING, wallApproach.getState()); // APPROACHING → SLOWING sensor.setDistance(25.0); wallApproach.update(); assertEquals(SLOWING, wallApproach.getState()); // SLOWING → STOPPED sensor.setDistance(10.0); wallApproach.update(); assertEquals(STOPPED, wallApproach.getState()); // STOPPED → STOPPED (stays stopped) wallApproach.update(); assertEquals(STOPPED, wallApproach.getState()); } ``` ### Performance Testing Verify code runs fast enough: ```java @Test void testUpdatePerformance() { long startTime = System.nanoTime(); for (int i = 0; i < 1000; i++) { wallApproach.update(); } long elapsedMs = (System.nanoTime() - startTime) / 1_000_000; assertTrue(elapsedMs < 100, "1000 updates should complete in < 100ms"); } ``` ## Conclusion Testing without hardware is **not a compromise** - it's actually **better**: - Faster development - Safer testing - More thorough coverage - Professional practices This is how real robotics companies (Boston Dynamics, Tesla, SpaceX) develop robots. Your students are learning the same techniques used to land rockets and build autonomous vehicles!