Sui Move - Unit Test 看这里 (Test Scenario)

  • Mindfrog
  • 更新于 2024-05-07 11:53
  • 阅读 241

主要讲一下如何使用test_scenario 进行复杂的测试,辅以一些例子尽量让朋友们掌握并且可以运用到项目当中。

主要会分为两部分来讲解:

  1. Test Annotation主要讲一下关于测试注释的基本用法和一些个小例子。
  2. Test Scenario主要讲一下如何使用test_scenario 进行复杂的测试,辅以一些例子尽量让朋友们掌握并且可以运用到项目当中。

    Intro to Test Scenario

    test_scenario Module 提供了一个可以模拟多用户,多Transaction的场景,我们需要理解并与之交互的主要是Scenario对象。

public struct Scenario {
        txn_number: u64,
        ctx: TxContext,
    }

Scenario 对象维护了一个全局对象的池子,可以简单的理解所有在测试过程中的对象都会存储在这个池子中,因此这些对象可以通过像 `take_from_sender` 这样的函数来访问。下面介绍使用test_scenario需要掌握的知识点。

1. Begin & End 方法

  • Scenario对象模拟多交易序列,可以使用发送者地址进行初始化,其中开始和结束方法是我们一定会用到的:
    public fun begin(sender: address): Scenario 
    public fun end(scenario: Scenario): TransactionEffects
  • 简单的使用方法如下:
    // 初始化一个虚拟的交易地址,名称是addr,地址是@0xA
    let addr = @0xA;
    // 以addr作为发送方开始模拟多Transaction的Scenario,返回Scenario对象
    let mut scenario = test_scenario::begin(addr1);
    ...
    // 清除掉scenario对象
    test_scenario::end(scenario);  
  • 注意!因为Scenario对象不包含Drop能力,所以必须使用test_scenario::end在其作用域结束时显式清理掉它。

2. next_tx 方法

public fun next_tx(scenario: &mut Scenario, sender: address): TransactionEffects

Scenario推进到一个新的Transaction中,其中“sender”是交易发送者,所有转移的对象都会被移入到全局对象池中。换句话说,为了使用各种“take”方法来访问对象例如take_from_address_by_id,Transaction必须首先执行 next_tx方法来获取上一笔Transaction的结果(TransactionEffects)。 注意!! 如果共享或不可变对象被删除、传输或包装,或者无法返回 TransactionEffects 程序将中止。

  • TransactionEffects 对象 记录在测试中每一次Transaction的Effects
    public struct TransactionEffects has drop {
        /// The objects created this transaction
        created: vector<ID>,
        /// The objects written/modified this transaction
        written: vector<ID>,
        /// The objects deleted this transaction
        deleted: vector<ID>,
        /// The objects transferred to an account this transaction
        transferred_to_account: VecMap<ID, /* owner */ address>,
        /// The objects transferred to an object this transaction
        transferred_to_object: VecMap<ID, /* owner */ ID>,
        /// The objects shared this transaction
        shared: vector<ID>,
        /// The objects frozen this transaction
        frozen: vector<ID>,
        /// The number of user events emitted this transaction
        num_user_events: u64,
    }

Example for Test Senario

我们来看一个简单的例子,

  • 定义一个Sword对象,它拥有Magic和Strength字段。
  • sword_create方法接收magic,strength值,并且返回一个Sword对象。
  • 分别为Sword对象的两个属性定义Get方法。

    public struct Sword has key, store{
        id:UID,
        magic: u64,
        strength:u64,
    }
    
    public fun sword_create(magic:u64,strength:u64,ctx: & mut TxContext):Sword{
        let sword = Sword {
            id:object::new(ctx),
            magic:magic,
            strength:strength,
        };
        sword
    }
    
    public fun magic(sword:&Sword):u64 {
        sword.magic
    }
    
    public fun strength(sword:&Sword):u64 {
        sword.strength
    }

    下面是Scenario测试代码:

    #[test]
    fun test_sword_transactions() {
        use sui::test_scenario;
    
        // 创建两个变量代表两个不一样的地址
        let initial_owner = @0xCAFE;
        let final_owner = @0xFACE;
    
        // 使用initial_owner来开启test_scenario,也是测试的第一个tx;
        let mut scenario = test_scenario::begin(initial_owner);
        {
        // 创建Sword对象,并transfer给initial_owner;
        let sword = sword_create(42, 7, scenario.ctx());
        transfer::public_transfer(sword, initial_owner);
        };
    
        // 第二个tx同样也由initial_owner来启动
        scenario.next_tx(initial_owner);
        {
        // 把Sword从initial_owner的地址中拿出来,并transfer给final_owner;
        let sword = scenario.take_from_sender<Sword>();       
        transfer::public_transfer(sword, final_owner);
        };
    
        // 第三个tx由final_owner来启动
        scenario.next_tx(final_owner);
        {
        // 把Sword从final_owner的地址中拿出来
        let sword = scenario.take_from_sender<Sword>();
        // 这里做一下属性验证看是否和之前创建的时候一致
        assert!(sword.magic() == 42 && sword.strength() == 7, 1);
        // 因为我们的Sword没有Drop能力,所以这里我们需要还回去,或者transfer给其他地址
        scenario.return_to_sender(sword)
        };
        scenario.end();
    }

End

点赞 3
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Mindfrog
Mindfrog
0x6e43...Ff69
写一句话让别人不了解你