測試康威的生命遊戲
現在我們已經使用 JavaScript 在瀏覽器中呈現了生命遊戲的 Rust 實作,讓我們來談談如何測試我們用 Rust 生成的 WebAssembly 函數。
我們將測試我們的 tick
函數,以確保它能提供我們預期的輸出。
接下來,我們要在 wasm_game_of_life/src/lib.rs
文件中現有的 impl Universe
區塊內建立一些設置器和獲取器函數。我們將建立 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
文件中建立另一個沒有 #[wasm_bindgen]
屬性的 impl Universe
區塊。我們需要一些用於測試的函數,這些函數不希望暴露給我們的 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
crate 和 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
的單元格來建立我們的太空船。在 expected_spaceship
函數中,輸入太空船在 tick 後的位置是手動計算的。您可以自行確認輸入太空船在一次 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-pack test --firefox --headless
在 wasm-game-of-life
目錄中運行測試。