Aptos合约开发之单元测试和函数调用

  • 欧皇.eth
  • 更新于 2022-09-14 09:12
  • 阅读 2748

Move和Aptos的单元测试和函数调用。

一、前言

在我们开始动手对Resource进行增删改查等操作之前,我们有必要先熟悉Move和Aptos的单元测试和函数调用。否则,我们无法保障程序的质量。

二、关键词

模块化、模块和脚本、Move单元测试、Aptos单元测试、函数调用、脚本调用

三、模块化

什么是模块化?对搞过工程项目的来讲,模块化并不陌生。模块化就是把功能相似的代码都放在一起,要用的时候能快速找到。

在Java web项目里,可以创建Component、Service、Controller、Repository等文件夹来实现模块化。

在Python项目里,一个.py文件就是一个模块。

在Move项目里,用Module关键字来表示模块。而用Script脚本表示传统语言(python、java、c等)中main函数的概念。因为一个程序只能有一个main函数。所以,单个Script脚本文件中的函数数量不能超过一个,这是再自然不过的事情。

Move has two different types of programs: Modules and Scripts. Modules are libraries that define struct types along with functions that operate on these types. Scripts are executable entrypoints similar to a main function in a conventional language. ---引自《Move Book》

四、Script脚本

Script脚本可以理解为main函数,在脚本里可以进行模块函数调用。

//sources/debug_script.move
script {
    use std::debug;
    const ONE: u64 = 1;
    // bool literals (true, false)
    // u64 literals (e.g., 10, 58)
    // address literals (e.g., 0x12, 0x0000000000000000000000000000000f)
    // hexadecimal strings (e.g., 'x"0012"' will parse as the vector<u8> value [00, 12])
    // ASCII strings (e.g., 'b"hi"' will parse as the vector<u8> value [68, 69])
    fun debug_script(x:u64 , y:bool ,addr:address) {
        let sum = x + ONE;
        debug::print(&sum);
        debug::print(&y);
        debug::print(&addr);
    }
}

4.1 在沙盒环境执行script脚本

控制台输入move sandbox run sources/debug_script.move --args 33 true 0xf。 通过使用--args向脚本main函数传参。执行结果如下:

ouhuang@LAPTOP-HM465BTT:~/learn_move$ move sandbox run sources/debug_script.move --args  33  true  0xf  
[debug] 34
[debug] true
[debug] 0000000000000000000000000000000F

注意!script脚本的特点

  • 只能定义一个fun
  • 该函数不能有返回值
  • Scripts have very limited power—they cannot declare friends, struct types or access global storage. Their primary purpose is to invoke module functions.

五、Module模块

module Test{...}模块嵌套在address 0x4{...}里,这种写法表示Test模块经publish后会被放到账户0x4的名下。所以,才可以使用0x4::Test::函数名这种形式进行调用。

// sources/Test.move
module 0x4::Test {
    use std::signer;
    use std::debug;

    struct Resource has key { i: u64 }

    public fun publish(account: &signer) {
        move_to(account, Resource { i: 10 });
    }
    //Comments must be written in English, not in Chinese 
    public fun write(account: &signer, i: u64) acquires Resource {
        if (!exists<Resource>(signer::address_of(account))){
            debug::print(&b"not exists");
            move_to(account, Resource { i: 11 });
        }else{
            borrow_global_mut<Resource>(signer::address_of(account)).i = i;
            debug::print(&borrow_global_mut<Resource>(signer::address_of(account)).i);
        }

    }

    public fun unpublish(account: &signer) acquires Resource {
        let Resource { i: _ } = move_from(signer::address_of(account));
    }

    #[test(account = @0xf)]
    fun  test_publish(account: signer) {
        publish(&account);
    }

    #[test(account = @0xf)]
    fun test_write(account: signer) acquires Resource {
        publish(&account);
        write(&account, 333);
    }
}

5.1 模块编译

使用move build编译sources下的move代码。

ouhuang@LAPTOP-HM465BTT:~/learn_move$ move build
INCLUDING DEPENDENCY MoveNursery
INCLUDING DEPENDENCY MoveStdlib
BUILDING learn_move

5.2 模块发布

在沙盒环境使用move sandbox publish -v发布字节码到0x4名下。

move sandbox publish -v

ouhuang@LAPTOP-HM465BTT:~/learn_move$ move sandbox publish -v
Found 1 modules
Updating an existing module 00000000000000000000000000000004::Test (wrote 354 bytes)
Wrote 354 bytes of module ID's and code

检查0x4地址下是否保存Test模块。

ouhuang@LAPTOP-HM465BTT:~/learn_move$ ls storage/0x00000000000000000000000000000004/modules
Test.mv

5.3 模块单元测试

在Move语言里,编写单元测试函数需要注意以下几点:

  • test传参只能传signer,不能传其他类型的参数
  • 每个测试结束后,会清除相关的上下文。所以write的前提需要先publish。

以上两点参考自《Move Book》:https://diem.github.io/move/unit-testing.html

Only parameters with a type of signer are supported as test parameters. If a non-signer parameter is supplied, the test will result in an error when run.

使用move test执行单元测试函数。

let value : u64  = 444;
#[test(account = @0xf , i = @value)]
fun test_write(account: signer,i: u64) acquires Resource {
    write(&account,i);
}
//错误 只能传递signer参数

#[test(account = @0xf)]
fun test_write(account: signer) acquires Resource {
    write(&account, 33);
}
//错误  每个测试结束后,会清除相关的上下文.也就是说每个
测试是独立的。write的前提需要先执行publish。

#[test(account = @0xf)]
fun test_write(account: signer) acquires Resource {
    publish(&account);
    write(&account, 33);
}
// 正确  执行结果如下所示:
ouhuang@LAPTOP-HM465BTT:~/learn_move$ move test
INCLUDING DEPENDENCY MoveNursery
INCLUDING DEPENDENCY MoveStdlib
BUILDING learn_move
Running Move unit tests
[ PASS    ] 0x4::Test::test_publish
[debug] 335
[ PASS    ] 0x4::Test::test_write
Test result: OK. Total tests: 2; passed: 2; failed: 0

5.4 模块函数调用

编写脚本,调用0x4名下的Test模块的publish函数。

//sources/test_script.move
script {
    use std::debug;
    use 0x4::Test;

    fun debug_script(account: signer) {
        Test::publish(&account);
        Test::write(&account, 333);
        debug::print(&b"Success!");
    }
}

5.4.1 执行函数调用脚本

move sandbox run sources/test_script.move --signers 0xf -v --dry-run在这条命令中,如果去掉--dry-run参数执行,会立即提交结果。

ouhuang@LAPTOP-HM465BTT:~/learn_move$ move sandbox run sources/test_script.move   --signers 0xf -v --dry-run
[debug] 333
[debug] (&) [83, 117, 99, 99, 101, 115, 115, 33]
Changed resource(s) under 1 address(es):
  Changed 1 resource(s) under address 0000000000000000000000000000000F:
    Added type 0x4::Test::Resource: [77, 1, 0, 0, 0, 0, 0, 0] (wrote 40 bytes)
      key 0x4::Test::Resource {
          i: 333
      }
Wrote 40 bytes of resource ID's and data
Discarding changes; re-run without --dry-run if you would like to keep them.

六、Aptos项目

Aptos是基于Move语言的智能合约框架,链上的合约是要被调用的,用户可以直接调用被entry关键字修饰的module中的函数。

set_message is a script function allowing it to be called directly by transactions.

6.1 单元测试

在Aptos框架下,单元测试函数写法和move的写法相同,唯一不同的是,单元测试执行的命令不同。

move项目是move test。在aptos框架下是aptos move test --package-dir .

ouhuang@LAPTOP-HM465BTT:~/learn_move$ aptos move test --package-dir .
INCLUDING DEPENDENCY MoveNursery
INCLUDING DEPENDENCY MoveStdlib
BUILDING learn_move
Running Move unit tests
[ PASS    ] 0x4::Test::test_publish
[debug] 335
[ PASS    ] 0x4::Test::test_write
Test result: OK. Total tests: 2; passed: 2; failed: 0
{
  "Result": "Success"
}

ouhuang@LAPTOP-HM465BTT:~/learn_move$ move test
INCLUDING DEPENDENCY MoveNursery
INCLUDING DEPENDENCY MoveStdlib
BUILDING learn_move
Running Move unit tests
[ PASS    ] 0x4::Test::test_publish
[debug] 335
[ PASS    ] 0x4::Test::test_write
Test result: OK. Total tests: 2; passed: 2; failed: 0

6.2 函数调用

经过aptos move publish后的合约会部署在Aptos链上,对链上合约的函数调用如果会改变状态,则被叫做发起交易。这个概念和Solidity是一样的。调用函数的方式有以下三种:

  • 使用区块链浏览器链接钱包后进行调用
  • 在终端使用命令进行调用
  • 通过python、js、rust的sdk进行调用

例:python sdk地址:https://aptos.dev/sdks/python-sdk

//合约编译
sudo aptos move compile --package-dir contract/sources/

//合约测试
sudo aptos move test --package-dir contract/

//合约发布
sudo aptos move publish  --package-dir .

//函数调用:在终端,使用命令调用某个地址下的函数。
sudo aptos move run --function-id fbd4140a63e8fe7d6e9e25aff78e11876b1b6c21bc8d34b51cbfff40ca03164b::Test2::publish 

至此,我们对Move项目和Aptos项目的单元测试及函数调用的研究就暂时告一段落。接下来是对Resource的操作教程。相信很快我们就能发现自己的ERC-20合约。^_^

七、参考文档:

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

0 条评论

请先 登录 后评论
欧皇.eth
欧皇.eth
一位懂区块链的项目经理。 微信公众号:一位懂技术的PM