From 7c255281767c6e47cdb82df364a0ae96ca4a50dc Mon Sep 17 00:00:00 2001 From: Wybe Westra Date: Sat, 21 Jan 2023 14:54:48 +0100 Subject: [PATCH] Show basic application testing (#2896) --- tests/how_to_test_full_app.rs | 113 ++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/how_to_test_full_app.rs diff --git a/tests/how_to_test_full_app.rs b/tests/how_to_test_full_app.rs new file mode 100644 index 0000000000000..594d3a1bb6c93 --- /dev/null +++ b/tests/how_to_test_full_app.rs @@ -0,0 +1,113 @@ +use bevy::prelude::*; + +const DEFAULT_MANA: u32 = 10; + +#[derive(Component)] +struct Player { + mana: u32, +} + +fn window_title_system(mut windows: Query<&mut Window>) { + for (index, mut window) in windows.iter_mut().enumerate() { + window.title = format!("This is window {index}!"); + } +} + +fn spawn_player(mut commands: Commands) { + commands.spawn(Player { mana: DEFAULT_MANA }); +} + +fn spell_casting(mut player: Query<&mut Player>, keyboard_input: Res>) { + if keyboard_input.just_pressed(KeyCode::Space) { + let Ok(mut player) = player.get_single_mut() else { + return; + }; + + if player.mana > 0 { + player.mana -= 1; + } + } +} + +fn create_test_app() -> App { + let mut app = App::new(); + + // Note how we use `MinimalPlugins` instead of `DefaultPlugins`. + // This is what allows the test to run without a window, or real user input. + app.add_plugins(MinimalPlugins); + // Inserting a KeyCode input resource allows us to inject keyboard inputs, + // as if the user had pressed them. + app.insert_resource(Input::::default()); + + // Spawning a fake window allows testing systems that require a window. + app.world.spawn(Window::default()); + + app +} + +fn add_game_systems(app: &mut App) { + // This could be a subset of your game's systems, or the entire app. + // As long as you make sure to add a fake version of inputs, windows, and any + // other things that your game's systems rely on. + app.add_startup_system(spawn_player) + .add_startup_system(window_title_system) + .add_system(spell_casting); +} + +#[test] +fn test_player_spawn() { + let mut app = create_test_app(); + add_game_systems(&mut app); + + // The `update` function needs to be called at least once for the startup + // systems to run. + app.update(); + + // Now that the startup systems have run, we can check if the player has + // spawned as expected. + let player = app.world.query::<&Player>().get_single(&app.world); + assert!(player.is_ok(), "There should be exactly 1 player."); + assert_eq!( + player.unwrap().mana, + DEFAULT_MANA, + "Player does not have expected starting mana." + ); +} + +#[test] +fn test_spell_casting() { + let mut app = create_test_app(); + add_game_systems(&mut app); + + // We simulate pressing `space` to trigger the spell casting system. + app.world + .resource_mut::>() + .press(KeyCode::Space); + // Allow the systems to realize space got pressed. + app.update(); + + // The spell casting should have used up a single mana. + let player = app.world.query::<&Player>().single(&app.world); + assert_eq!(player.mana, DEFAULT_MANA - 1); + + // Clear the `just_pressed` status for all `KeyCode`s + app.world.resource_mut::>().clear(); + app.update(); + + // No extra spells should have been cast, so no mana should have been lost. + let player = app.world.query::<&Player>().single(&app.world); + assert_eq!(player.mana, DEFAULT_MANA - 1); +} + +#[test] +fn test_faking_windows() { + let mut app = create_test_app(); + add_game_systems(&mut app); + + // The `update` function needs to be called at least once for the startup + // systems to run. + app.update(); + + let window = app.world.query::<&Window>().single(&app.world); + assert_eq!(window.title, "This is window 0!") +}