Skip to content

Commit 7c25528

Browse files
committed
Show basic application testing (#2896)
1 parent 02637b6 commit 7c25528

File tree

1 file changed

+113
-0
lines changed

1 file changed

+113
-0
lines changed

tests/how_to_test_full_app.rs

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
use bevy::prelude::*;
2+
3+
const DEFAULT_MANA: u32 = 10;
4+
5+
#[derive(Component)]
6+
struct Player {
7+
mana: u32,
8+
}
9+
10+
fn window_title_system(mut windows: Query<&mut Window>) {
11+
for (index, mut window) in windows.iter_mut().enumerate() {
12+
window.title = format!("This is window {index}!");
13+
}
14+
}
15+
16+
fn spawn_player(mut commands: Commands) {
17+
commands.spawn(Player { mana: DEFAULT_MANA });
18+
}
19+
20+
fn spell_casting(mut player: Query<&mut Player>, keyboard_input: Res<Input<KeyCode>>) {
21+
if keyboard_input.just_pressed(KeyCode::Space) {
22+
let Ok(mut player) = player.get_single_mut() else {
23+
return;
24+
};
25+
26+
if player.mana > 0 {
27+
player.mana -= 1;
28+
}
29+
}
30+
}
31+
32+
fn create_test_app() -> App {
33+
let mut app = App::new();
34+
35+
// Note how we use `MinimalPlugins` instead of `DefaultPlugins`.
36+
// This is what allows the test to run without a window, or real user input.
37+
app.add_plugins(MinimalPlugins);
38+
// Inserting a KeyCode input resource allows us to inject keyboard inputs,
39+
// as if the user had pressed them.
40+
app.insert_resource(Input::<KeyCode>::default());
41+
42+
// Spawning a fake window allows testing systems that require a window.
43+
app.world.spawn(Window::default());
44+
45+
app
46+
}
47+
48+
fn add_game_systems(app: &mut App) {
49+
// This could be a subset of your game's systems, or the entire app.
50+
// As long as you make sure to add a fake version of inputs, windows, and any
51+
// other things that your game's systems rely on.
52+
app.add_startup_system(spawn_player)
53+
.add_startup_system(window_title_system)
54+
.add_system(spell_casting);
55+
}
56+
57+
#[test]
58+
fn test_player_spawn() {
59+
let mut app = create_test_app();
60+
add_game_systems(&mut app);
61+
62+
// The `update` function needs to be called at least once for the startup
63+
// systems to run.
64+
app.update();
65+
66+
// Now that the startup systems have run, we can check if the player has
67+
// spawned as expected.
68+
let player = app.world.query::<&Player>().get_single(&app.world);
69+
assert!(player.is_ok(), "There should be exactly 1 player.");
70+
assert_eq!(
71+
player.unwrap().mana,
72+
DEFAULT_MANA,
73+
"Player does not have expected starting mana."
74+
);
75+
}
76+
77+
#[test]
78+
fn test_spell_casting() {
79+
let mut app = create_test_app();
80+
add_game_systems(&mut app);
81+
82+
// We simulate pressing `space` to trigger the spell casting system.
83+
app.world
84+
.resource_mut::<Input<KeyCode>>()
85+
.press(KeyCode::Space);
86+
// Allow the systems to realize space got pressed.
87+
app.update();
88+
89+
// The spell casting should have used up a single mana.
90+
let player = app.world.query::<&Player>().single(&app.world);
91+
assert_eq!(player.mana, DEFAULT_MANA - 1);
92+
93+
// Clear the `just_pressed` status for all `KeyCode`s
94+
app.world.resource_mut::<Input<KeyCode>>().clear();
95+
app.update();
96+
97+
// No extra spells should have been cast, so no mana should have been lost.
98+
let player = app.world.query::<&Player>().single(&app.world);
99+
assert_eq!(player.mana, DEFAULT_MANA - 1);
100+
}
101+
102+
#[test]
103+
fn test_faking_windows() {
104+
let mut app = create_test_app();
105+
add_game_systems(&mut app);
106+
107+
// The `update` function needs to be called at least once for the startup
108+
// systems to run.
109+
app.update();
110+
111+
let window = app.world.query::<&Window>().single(&app.world);
112+
assert_eq!(window.title, "This is window 0!")
113+
}

0 commit comments

Comments
 (0)