Skip to main content

測試 (Testing)

測試是軟體開發中至關重要的一環,尤其是在安全性與正確性至上的區塊鏈應用中。在本節中,我們將介紹 Move 測試的基礎知識,包括如何有效地編寫和組織測試。

#[test] 屬性

Move 中的測試是標記有 #[test] 屬性的函式。此屬性告訴編譯器該函式是一個測試函式,應該在執行測試時運行。測試函式是普通函式,但它們必須不接收任何參數且沒有傳回值。它們會從位元組碼中排除,且永遠不會被發佈。

module book::testing;

#[test_only]
use std::unit_test::assert_eq;

// test 屬性放置在 `fun` 關鍵字之前(可以放在上方,
// 也可以直接放在 `fun` 關鍵字之前,如 `#[test] fun my_test() { ... }`)
// 在此範例中,測試的名稱將是 `book::testing::simple_test`。
#[test]
fun simple_test() {
let sum = 2 + 2;
assert_eq!(sum, 4);
}

// 此測試的名稱將是 `book::testing::more_advanced_test`。
#[test] fun more_advanced_test() {
let sum = 2 + 2 + 2;
assert_eq!(sum, 4);
}

執行測試

要執行測試,您可以使用 sui move test 指令。此指令會首先在 測試模式 下編譯套件,然後執行套件中找到的所有測試。在測試模式下,sources/tests/ 目錄中的模組都會被處理並執行其中的測試。

$ sui move test
> UPDATING GIT DEPENDENCY https://github.com/MystenLabs/sui.git
> INCLUDING DEPENDENCY Bridge
> INCLUDING DEPENDENCY DeepBook
> INCLUDING DEPENDENCY SuiSystem
> INCLUDING DEPENDENCY Sui
> INCLUDING DEPENDENCY MoveStdlib
> BUILDING book
> Running Move unit tests
> ...

使用 #[expected_failure] 測試失敗情況

針對預期失敗的情況,可以使用 #[expected_failure] 標記測試。當此屬性添加到 #[test] 函式時,會告訴編譯器該測試預期會失敗。當您想測試某個函式在滿足特定條件時是否會失敗,這非常有用。

注意:此屬性只能添加到 #[test] 函式。

該屬性可以接收一個參數,指定測試失敗時預期傳回的中斷程式碼 (abort code)。如果測試傳回的中斷程式碼與參數中指定的不符,測試將失敗。同樣地,如果執行沒有導致中斷,測試也會失敗。

module book::testing_failure;

const EInvalidArgument: u64 = 1;

#[test]
#[expected_failure(abort_code = 0)]
fun test_fail() {
abort 0 // 以程式碼 0 中斷
}

// 屬性可以組合在一起
#[test, expected_failure(abort_code = EInvalidArgument)]
fun test_fail_1() {
abort EInvalidArgument // 以程式碼 EInvalidArgument 中斷
}

abort_code 參數可以使用測試模組中定義的常數,也可以從其他模組匯入。這是常數唯一可以在其他模組中被使用和「存取」的情況。

使用 #[test_only] 提供測試工具

在某些情況下,讓測試環境能夠存取某些內部函式或功能會很有幫助。這可以簡化測試過程並實現更徹底的測試。然而,重要的是要記住,這些函式不應包含在最終發佈的套件中。這就是 #[test_only] 屬性派上用場的地方。

module book::testing;

#[test_only]
use std::unit_test::assert_eq;

// 使用了 `secret` 函式的公開函式。
public fun multiply_by_secret(x: u64): u64 {
x * secret()
}

/// 不對外公開的私有函式。
fun secret(): u64 { 100 }

#[test_only]
/// 此函式僅供測試目的使用,可用於測試及其他僅限測試的函式中。
/// 注意可見性 — 對於 `#[test_only]`,通常使用 `public` 可見性。
public fun secret_for_testing(): u64 {
secret()
}

#[test]
// 在測試環境中,我們可以存取 `secret_for_testing` 函式。
fun test_multiply_by_secret() {
let expected = secret_for_testing() * 2;
assert_eq!(multiply_by_secret(2), expected);
}

標記為 #[test_only] 的函式將對測試環境開放,如果其可見性設為 public,則也會對其他模組開放。

延伸閱讀