测试康威的生命游戏
现在我们已经有了在浏览器中使用 JavaScript 渲染的生命游戏 Rust 实现,让我们来谈谈如何测试我们用 Rust 生成的 WebAssembly 函数。
我们将测试我们的 tick
函数,以确保它能给出我们期望的输出。
接下来,我们想在 wasm_game_of_life/src/lib.rs
文件中现有的 impl Universe
块内创建一些 setter 和 getter 函数。我们将创建一个 set_width
和 set_height
函数,以便我们可以创建不同大小的 Universe
。
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen] impl Universe { // ... /// Set the width of the universe. /// /// Resets all cells to the dead state. pub fn set_width(&mut self, width: u32) { self.width = width; self.cells = (0..width * self.height).map(|_i| Cell::Dead).collect(); } /// Set the height of the universe. /// /// Resets all cells to the dead state. pub fn set_height(&mut self, height: u32) { self.height = height; self.cells = (0..self.width * height).map(|_i| Cell::Dead).collect(); } } #}
我们将在 wasm_game_of_life/src/lib.rs
文件中创建另一个 impl Universe
块,但没有 #[wasm_bindgen]
属性。我们有一些用于测试的函数,我们不想将其暴露给 JavaScript。用 Rust 生成的 WebAssembly 函数不能返回借用引用。尝试用该属性编译用 Rust 生成的 WebAssembly,并查看你得到的错误。
我们将编写 get_cells
的实现,以获取 Universe
的 cells
内容。我们还将编写一个 set_cells
函数,以便我们可以将 Universe
中特定行和列的 cells
设置为 Alive
。
# #![allow(unused_variables)] #fn main() { impl Universe { /// Get the dead and alive values of the entire universe. pub fn get_cells(&self) -> &[Cell] { &self.cells } /// Set cells to be alive in a universe by passing the row and column /// of each cell as an array. pub fn set_cells(&mut self, cells: &[(u32, u32)]) { for (row, col) in cells.iter().cloned() { let idx = self.get_index(row, col); self.cells[idx] = Cell::Alive; } } } #}
现在我们将创建 wasm_game_of_life/tests/web.rs
文件中的测试。
在我们这样做之前,该文件中已经有一个可用的测试。你可以通过在 wasm-game-of-life
目录中运行 wasm-pack test --chrome --headless
来确认用 Rust 生成的 WebAssembly 测试是否有效。你也可以使用 --firefox
、--safari
和 --node
选项在这些浏览器中测试你的代码。
在 wasm_game_of_life/tests/web.rs
文件中,我们需要导出我们的 wasm_game_of_life
箱子和 Universe
类型。
# #![allow(unused_variables)] #fn main() { extern crate wasm_game_of_life; use wasm_game_of_life::Universe; #}
在 wasm_game_of_life/tests/web.rs
文件中,我们想创建一些宇宙飞船构建器函数。
我们想要一个用于我们将在其上调用 tick
函数的输入宇宙飞船,以及我们希望在一次 tick 后得到的预期宇宙飞船。我们在 input_spaceship
函数中选择了我们想要初始化为 Alive
的单元格来创建我们的宇宙飞船。input_spaceship
一次 tick 后 expected_spaceship
函数中宇宙飞船的位置是手动计算的。你可以自己确认输入宇宙飞船的单元格在一次 tick 后是否与预期宇宙飞船相同。
# #![allow(unused_variables)] #fn main() { #[cfg(test)] pub fn input_spaceship() -> Universe { let mut universe = Universe::new(); universe.set_width(6); universe.set_height(6); universe.set_cells(&[(1,2), (2,3), (3,1), (3,2), (3,3)]); universe } #[cfg(test)] pub fn expected_spaceship() -> Universe { let mut universe = Universe::new(); universe.set_width(6); universe.set_height(6); universe.set_cells(&[(2,1), (2,3), (3,2), (3,3), (4,2)]); universe } #}
现在我们将编写 test_tick
函数的实现。首先,我们创建 input_spaceship()
和 expected_spaceship()
的实例。然后,我们在 input_universe
上调用 tick
。最后,我们使用 assert_eq!
宏调用 get_cells()
来确保 input_universe
和 expected_universe
具有相同的 Cell
数组值。我们在代码块中添加 #[wasm_bindgen_test]
属性,以便我们可以测试用 Rust 生成的 WebAssembly 代码,并使用 wasm-pack test
测试 WebAssembly 代码。
# #![allow(unused_variables)] #fn main() { #[wasm_bindgen_test] pub fn test_tick() { // Let's create a smaller Universe with a small spaceship to test! let mut input_universe = input_spaceship(); // This is what our spaceship should look like // after one tick in our universe. let expected_universe = expected_spaceship(); // Call `tick` and then see if the cells in the `Universe`s are the same. input_universe.tick(); assert_eq!(&input_universe.get_cells(), &expected_universe.get_cells()); } #}
通过在 wasm-game-of-life
目录中运行 wasm-pack test --firefox --headless
来运行测试。