测试场景:管理交易

如果你还记得对象、&mut TxContexttx_context 模块,你可能会问这些在测试中是如何设置的。 答案是默认情况下它们不是。这可能会在编写测试时导致令人困惑的失败,因为这些 tx_context 通常用于创建对象或确定交易的发送者。 Move 单元测试仅在Move VM 上运行,不包含区块链的其他组件。为了确保 tx_context 以及 Sui 系统的其他部分正常工作,开发者可以使用 test_scenario

use sui::test_scenario::{Self, Scenario};

#[test]
public fun my_test() {
    let scenario_val = test_scenario::begin(@0x123);
    let scenario = &mut scenario_val;

    test_scenario::next_tx(scenario, @0x123);
    // 测试代码

    test_scenario::end(scenario_val);
}

在整个测试过程中,有 3 个函数可以从 test_scenario 调用:

  • test_scenario::begin - 这个函数初始化测试场景并返回一个 Scenario 对象。这个对象用于跟踪测试场景的状态。
  • test_scenario::next_tx - 这个函数用于模拟一个交易。它接受一个 Scenario 对象和一个发送者地址作为参数。这个函数用于模拟特定发送者的交易。
  • test_scenario::end : 这个函数用于结束测试场景。它接受一个 Scenario 对象作为参数,并清理测试场景。

使用这些函数,测试所需的一切都应该已经设置好。在某些情况下,开发者可能会明确表示每个测试代码块的交易边界,使用块 { ... } 来实现:

#[test]
fun my_test {
    // === 第三笔交易 ===
    // 下一笔交易 - Fran 查看她的库存并找到了那本书
    // 她决定将书还给 Manny,并自己再买一本
    test_scenario::next_tx(&mut scenario, fran);
    {
        // 可以通过 ID 从发送者那里获取对象(如果有多个)
        // 或者如果只有一个对象,可以使用:`take_from_sender<T>(&scenario)`
        let book = test_scenario::take_from_sender_by_id<LittleBookOfCalm>(&scenario, book_id);
        /// 将书送还给 Manny
        sui::transfer::transfer(book, manny);

        // 现在重复之前的步骤
        let store = test_scenario::take_shared<BlackBooks>(&scenario);
        let ctx = test_scenario::ctx(&mut scenario);
        let coin = coin::mint_for_testing<SUI>(5_000_000_000, ctx);

        // 与之前相同 - 购买这本书
        let book = purchase(&mut store, coin, ctx);
        sui::transfer::transfer(book, fran);

        // 别忘了归还
        test_scenario::return_shared(store);
    };

    // === 第四笔交易 ===
    // 最后一笔交易 - Bernard 收取收益并将商店转让给 Fran
    test_scenario::next_tx(&mut scenario, bernard);
    {
        let store = test_scenario::take_shared<BlackBooks>(&scenario);
        let cap = test_scenario::take_from_sender<StoreOwnerCap>(&scenario);
        let ctx = test_scenario::ctx(&mut scenario);
        let coin = collect(&mut store, &cap, ctx);

        sui::transfer::public_transfer(coin, bernard);
        sui::transfer::transfer(cap, fran);
        test_scenario::return_shared(store);
    };
}