測試康威生命遊戲
現在我們的 Rust 實作版本的生命遊戲已經透過 JavaScript 呈現在瀏覽器中,我們來討論一下如何測試 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
,即可執行測試。