# Testing Strategy Enhancement ## Current Testing State ### Existing Tests - ✅ GravityTests.cpp - Basic gravity manager testing - ✅ Catch2 framework integration - ✅ CTest integration in CMake ### Coverage Gaps - ❌ Game logic testing (piece movement, rotation, line clearing) - ❌ Collision detection testing - ❌ Scoring system testing - ❌ State management testing - ❌ Integration tests - ❌ Performance tests ## Comprehensive Testing Strategy ### 1. Unit Tests Expansion ```cpp // tests/GameLogicTests.cpp TEST_CASE("Piece Movement", "[game][movement]") { Game game(0); Piece originalPiece = game.current(); SECTION("Move left when possible") { game.move(-1); REQUIRE(game.current().x == originalPiece.x - 1); } SECTION("Cannot move left at boundary") { // Move piece to left edge while (game.current().x > 0) { game.move(-1); } int edgeX = game.current().x; game.move(-1); REQUIRE(game.current().x == edgeX); // Should not move further } } // tests/CollisionTests.cpp TEST_CASE("Collision Detection", "[game][collision]") { Game game(0); SECTION("Piece collides with bottom") { // Force piece to bottom while (!game.isGameOver()) { game.hardDrop(); if (game.isGameOver()) break; } // Verify collision behavior } SECTION("Piece collides with placed blocks") { // Place a block manually // Test collision with new piece } } // tests/ScoringTests.cpp TEST_CASE("Scoring System", "[game][scoring]") { Game game(0); int initialScore = game.score(); SECTION("Single line clear") { // Set up board with almost complete line // Clear line and verify score increase } SECTION("Tetris (4 lines)") { // Set up board for Tetris // Verify bonus scoring } } ``` ### 2. Mock Objects for Testing ```cpp // tests/mocks/MockRenderer.h class MockRenderer : public IRenderer { private: mutable std::vector calls; public: void clear(uint8_t r, uint8_t g, uint8_t b, uint8_t a) override { calls.push_back("clear"); } void present() override { calls.push_back("present"); } SDL_Renderer* getSDLRenderer() override { return nullptr; // Mock implementation } const std::vector& getCalls() const { return calls; } void clearCalls() { calls.clear(); } }; // tests/mocks/MockAudioSystem.h class MockAudioSystem : public IAudioSystem { private: std::vector playedSounds; public: void playSound(const std::string& name) override { playedSounds.push_back(name); } void playMusic(const std::string& name) override { playedSounds.push_back("music:" + name); } void setMasterVolume(float volume) override { // Mock implementation } const std::vector& getPlayedSounds() const { return playedSounds; } }; ``` ### 3. Integration Tests ```cpp // tests/integration/StateTransitionTests.cpp TEST_CASE("State Transitions", "[integration][states]") { ApplicationManager app; // Mock dependencies SECTION("Loading to Menu transition") { // Simulate loading completion // Verify menu state activation } SECTION("Menu to Game transition") { // Simulate start game action // Verify game state initialization } } // tests/integration/GamePlayTests.cpp TEST_CASE("Complete Game Session", "[integration][gameplay]") { Game game(0); SECTION("Play until first line clear") { // Simulate complete game session // Verify all systems work together } } ``` ### 4. Performance Tests ```cpp // tests/performance/PerformanceTests.cpp TEST_CASE("Game Logic Performance", "[performance]") { Game game(0); SECTION("1000 piece drops should complete in reasonable time") { auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < 1000; ++i) { game.hardDrop(); if (game.isGameOver()) { game.reset(0); } } auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start); REQUIRE(duration.count() < 100); // Should complete in under 100ms } } // tests/performance/MemoryTests.cpp TEST_CASE("Memory Usage", "[performance][memory]") { SECTION("No memory leaks during gameplay") { size_t initialMemory = getCurrentMemoryUsage(); { Game game(0); // Simulate gameplay for (int i = 0; i < 100; ++i) { game.hardDrop(); if (game.isGameOver()) game.reset(0); } } size_t finalMemory = getCurrentMemoryUsage(); REQUIRE(finalMemory <= initialMemory + 1024); // Allow small overhead } } ``` ### 5. Property-Based Testing ```cpp // tests/property/PropertyTests.cpp TEST_CASE("Property: Game state consistency", "[property]") { Game game(0); SECTION("Score never decreases") { int previousScore = game.score(); // Perform random valid actions for (int i = 0; i < 100; ++i) { performRandomValidAction(game); REQUIRE(game.score() >= previousScore); previousScore = game.score(); } } SECTION("Board state remains valid") { for (int i = 0; i < 1000; ++i) { performRandomValidAction(game); REQUIRE(isBoardStateValid(game)); } } } ``` ### 6. Test Data Management ```cpp // tests/fixtures/GameFixtures.h class GameFixtures { public: static Game createGameWithAlmostFullLine() { Game game(0); // Set up specific board state return game; } static Game createGameNearGameOver() { Game game(0); // Fill board almost to top return game; } static std::vector createTetrisPieceSequence() { return {I, O, T, S, Z, J, L}; } }; ``` ## Test Automation & CI ### 1. GitHub Actions Configuration ```yaml # .github/workflows/tests.yml name: Tests on: [push, pull_request] jobs: test: runs-on: ${{ matrix.os }} strategy: matrix: os: [windows-latest, ubuntu-latest, macos-latest] build-type: [Debug, Release] steps: - uses: actions/checkout@v3 - name: Install dependencies run: | # Install vcpkg and dependencies - name: Configure CMake run: cmake -B build -DCMAKE_BUILD_TYPE=${{ matrix.build-type }} - name: Build run: cmake --build build --config ${{ matrix.build-type }} - name: Test run: ctest --test-dir build --build-config ${{ matrix.build-type }} ``` ### 2. Code Coverage ```cmake # Add to CMakeLists.txt option(ENABLE_COVERAGE "Enable code coverage" OFF) if(ENABLE_COVERAGE) target_compile_options(tetris PRIVATE --coverage) target_link_libraries(tetris PRIVATE --coverage) endif() ``` ## Quality Metrics Targets - **Unit Test Coverage**: > 80% - **Integration Test Coverage**: > 60% - **Performance Regression**: < 5% per release - **Memory Leak Detection**: 0 leaks in test suite - **Static Analysis**: 0 critical issues ## Implementation Priority 1. **Phase 1**: Core game logic unit tests (movement, rotation, collision) 2. **Phase 2**: Mock objects and dependency injection for testability 3. **Phase 3**: Integration tests for state management 4. **Phase 4**: Performance and memory tests 5. **Phase 5**: Property-based testing and fuzzing 6. **Phase 6**: CI/CD pipeline with automated testing