Snapshot Testing
This document provides an overview of snapshot testing in the Rummage project. For detailed implementation of the snapshot system itself, please see Snapshot System Testing.
Overview
Snapshot testing is a critical component of Rummage's testing strategy, allowing us to capture, store, and compare game states at different points in time. This approach is especially valuable for testing a complex rules engine like Magic: The Gathering, where many interactions can affect the game state in subtle ways.
Benefits of Snapshot Testing
- Deterministic Testing: Ensures game logic produces consistent, reproducible results
- Regression Prevention: Quickly identifies when changes affect existing functionality
- Complex State Verification: Makes it easier to verify complex game states
- Interaction Testing: Facilitates testing of multi-step card interactions
Snapshot Testing in MTG
In the context of Magic: The Gathering, snapshot testing helps verify:
- Rule Correctness: Ensures rules are applied correctly
- Card Interactions: Validates complex interactions between cards
- Format-Specific Rules: Tests special rules for formats like Commander
Integration with Other Testing Types
Snapshot testing complements other testing approaches:
- Unit Tests: Verify individual components in isolation
- Integration Tests: Test how components work together
- End-to-End Tests: Test the entire game flow
Using Snapshots in Tests
#![allow(unused)] fn main() { #[test] fn test_lightning_bolt_damage() { // Set up the game state let mut game = setup_test_game(); let player = game.add_player(20); // Player with 20 life // Cast Lightning Bolt targeting the player let lightning_bolt = game.create_card("Lightning Bolt"); game.cast(lightning_bolt, Some(player)); // Take a snapshot before resolution let pre_resolution = game.create_snapshot(); // Resolve the spell game.resolve_top_of_stack(); // Take a snapshot after resolution let post_resolution = game.create_snapshot(); // Verify the player's life total decreased by 3 assert_eq!(pre_resolution.get_player_life(player), 20); assert_eq!(post_resolution.get_player_life(player), 17); // Save the snapshots for future regression tests game.save_snapshot("lightning_bolt_pre", pre_resolution); game.save_snapshot("lightning_bolt_post", post_resolution); } }
Best Practices
- Targeted Snapshots: Capture only the relevant parts of game state
- Clear Naming: Use descriptive names for snapshots
- Minimal Setup: Keep test setup as simple as possible
- Deterministic Inputs: Ensure tests have consistent inputs (e.g., fix RNG seeds)
- Review Changes: Carefully review snapshot changes in pull requests