测试场景:管理交易
如果你还记得对象、&mut TxContext
和 tx_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);
};
}