基于Hardhat编写合约测试用例

这篇具有很好参考价值的文章主要介绍了基于Hardhat编写合约测试用例。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基于Hardhat编写合约测试用例

为智能合约编写自动化测试至关重要,毕竟写智能合约多多少少都会跟用户资金挂钩。

场景

这里假设自己正在开发一个NFT交易平台,这个平台可以让用户售卖自己的NFT,包括ERC721和ERC1155,并且用户可以指定购买者需要支付指定的ERC20 Token购买。
我们先确定自己的测试功能和目标,为了文章篇幅不要太长,我们就以卖家用户调用sell,创建售卖订单功能为目标做测试。

合约代码

我们需要4个合约文件:

  1. ERC20
  2. ERC721
  3. ERC1155
  4. NFTSwap(交易平台)

前三种合约最简单的,我们不需要自己再去实现,直接引用Openzeppelin的合约代码即可。
contracts目录下创建一个新的文件TestDependency.sol,并且把下面的代码粘贴进去

// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetMinterPauser.sol";
import "@openzeppelin/contracts/token/ERC721/presets/ERC721PresetMinterPauserAutoId.sol";
import "@openzeppelin/contracts/token/ERC1155/presets/ERC1155PresetMinterPauser.sol";

这样需要用到的ERC20,ERC721,ERC1155合约就会被编译到项目中

NFTSwap合约代码我只展示sell相关部分,足够测试即可
contracts目录下新建一个NFTSwap.sol合约,并粘贴下面的代码

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";

contract NFTSwap is Initializable {
    enum AssetType {
        ERC721,
        ERC1155
    }

    struct Asset {
        address Contract; // NFT Token地址
        uint256 TokenId; // Token id
        uint256 TokenValue; // Token Value, ERC721 为1
        AssetType Type; // NFT 类型
    }

    function __NFTSwap_init() public initializer {}

    function sell(
        Asset[] calldata assets, // 要售卖的NFT,可以同时售卖多个
        address paymentToken, // 指定接受购买支付的 ERC20 代币
        uint256 price // 售卖价格
    ) public virtual returns (uint256 goodsId) {
        // 创建售卖订单逻辑
        //.......
    }

编译合约

➜ npx hardhat compile
Compiled 36 Solidity files successfully

合约编译通过,下一步

引用测试工具包

修改项目根目录下的hardhat.config.js,添加对工具包的引用

require("@nomiclabs/hardhat-waffle");
require('@openzeppelin/hardhat-upgrades');

task("accounts", "Prints the list of accounts", async (taskArgs, hre) => {
  const accounts = await hre.ethers.getSigners();

  for (const account of accounts) {
    console.log(account.address);
  }
});

编写测试代码

这一部分是重点,我会把整个测试脚本文件先拆分讲解,并在文章最后附上完成的代码

引用

test目录下新建sell-test.js文件,我们将在这里编辑测试用例代码
先添加引用

const { expect, use } = require('chai'); //引入断言库
const { BigNumber } = require('ethers'); // bignumber一会儿要用到
const { deployContract, MockProvider, solidity } = require('ethereum-waffle'); 
const { ethers, upgrades } = require("hardhat");

use(solidity); // 这里是跟 chai 声明使用在solidity合约测试

定义测试套件和全局变量

因为我会在这个套件内定义多个测试用例,模拟多种场景,所以可以定义全局变量,减少代码重复

describe("Test NFTSwap.sell Interface", function () {
    var ERC20; 	// 存放要用到的ERC20
    var ERC721;	// 同上
    var ERC1155; // 同上
    var OWNER; // 这里是为了演示模拟多用户操作 
    var ADDR1; // 同上
}

定义beforeEach

beforeEach会在每个测试用例运行前先运行。可以通过定义beforeEach在每次测试前初始化环境,这样可以做到多个测试用例的数据不会相互影响,因为每次运行用例前,beforeEach都会重置环境

beforeEach(async () => {
    // 模拟不同的两个用户,比如测试完成的买卖流程就应该用 两个用户地址
    [OWNER, ADDR1] = await ethers.getSigners();

    // Owner 用户创建多个合约
    const ERC20PresetMinterPauser = await ethers.getContractFactory("ERC20PresetMinterPauser", OWNER);
    ERC20 = await ERC20PresetMinterPauser.deploy("TestERC20", "T20");

    const ERC721PresetMinterPauserAutoId = await ethers.getContractFactory("ERC721PresetMinterPauserAutoId", OWNER);
    ERC721 = await ERC721PresetMinterPauserAutoId.deploy("TestERC721", "T721", "https://t721.com");

    const ERC1155PresetMinterPauser = await ethers.getContractFactory("ERC1155PresetMinterPauser", OWNER);
    ERC1155 = await ERC1155PresetMinterPauser.deploy("https://t1155.com");

    const NFTSwap = await ethers.getContractFactory("NFTSwap");
    NFT_SWAP = await upgrades.deployProxy(NFTSwap, [], {
        initializer: '__NFTSwap_init'
    });
});

定义测试用例

这里我会定义三个测试用例,模拟售卖不同种类NFT,和同时售卖两种NFT的情况

第一个测试用例

创建售卖1个ERC721 Token订单成功

it("Should be sale an ERC721 token successful", async function () {
    // 确定 NFTSwap合约 部署完成
    await NFT_SWAP.deployed();

    // 确定 ERC721合约 部署完成
    await ERC721.deployed();

    // 增发 id=0 的token,并approve 给 NFTSwap
    var mintERC721Tx = await ERC721.connect(OWNER).mint(OWNER.address);
    await mintERC721Tx.wait();
    var approveERC721Tx = await ERC721.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
    await approveERC721Tx.wait();

    // 定义assets, assetType.ERC721 = 1
    var assets = [{ Contract: ERC721.address, TokenId: BigNumber.from(0), TokenValue: BigNumber.from(1), Type: 1 }]

    await ERC20.deployed();
    // 发起交易
    const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(1000000));
    await sellTx.wait()

    // 获取交易结果
    var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
    // 判断交易最终状态,必须为1,1表示合约执行成功
    expect(receipt.status).to.equal(1);
});
第二个测试用例

创建售卖1个ERC1155T oken订单成功

it("Should be sale an ERC1155 token successful", async function () {
    // 确定 NFTSwap合约 部署完成
    await NFT_SWAP.deployed();

    // 确定 ERC1155合约 部署完成
    await ERC1155.deployed();

    // 增发 id=0 的token,并approve 给 NFTSwap
    var mintERC1155Tx = await ERC1155.connect(OWNER).mint(OWNER.address, 1, 10, "0x");
    await mintERC1155Tx.wait();
    var approveERC1155Tx = await ERC1155.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
    await approveERC1155Tx.wait();

    // 定义assets, assetType.ERC1155 = 2
    var assets = [{ Contract: ERC1155.address, TokenId: BigNumber.from(1), TokenValue: BigNumber.from(1), Type: 2 }]

    await ERC20.deployed();
    const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(1000000));
    await sellTx.wait()

    var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
    expect(receipt.status).to.equal(1);
});
第三个测试用例

创建售卖 1个ERC721 Token + 1个ERC1155T oken 订单成功

it("Should be packet sale an ERC721 token and an ERC1155 token successful", async function () {
    // 确定 NFTSwap合约 部署完成
    await NFT_SWAP.deployed();

    // 确定 ERC721合约 部署完成
    await ERC721.deployed();

    // 增发 id=0 的ERC721 token,并approve 给 NFTSwap
    var mintERC721Tx = await ERC721.connect(OWNER).mint(OWNER.address);
    await mintERC721Tx.wait();
    var approveERC721Tx = await ERC721.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
    await approveERC721Tx.wait();

    // 确定 ERC1155合约 部署完成
    await ERC1155.deployed();

    // 增发 id=0 的ERC1155 token,并approve 给 NFTSwap
    var mintERC1155Tx = await ERC1155.connect(OWNER).mint(OWNER.address, 1, 10, "0x");
    await mintERC1155Tx.wait();
    var approveERC1155Tx = await ERC1155.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
    await approveERC1155Tx.wait();

    // 定义assets,这里是用两个 NFT Token的
    var assets = [{ Contract: ERC721.address, TokenId: BigNumber.from(0), TokenValue: BigNumber.from(1), Type: 1 },
    { Contract: ERC1155.address, TokenId: BigNumber.from(1), TokenValue: BigNumber.from(10), Type: 2 }]

    await ERC20.deployed();
    const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(200000));
    await sellTx.wait()

    var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
    expect(receipt.status).to.equal(1);
});

到这里,我们的测试脚本文件已经完成了,接下来直接运行测试脚本,查看测试结果就可以了

运行测试脚本

➜  npx hardhat test test/sell-test.js


  Test NFTSwap.sell Interface
    ✔ Should be sale an ERC721 token successful (120ms)
    ✔ Should be sale an ERC1155 token successful (99ms)
    ✔ Should be packet sale an ERC721 token and an ERC1155 token successful (177ms)


  3 passing (4s)

这里可以看到测试都通过

完整测试脚本代码

const { expect, use } = require('chai');
const { BigNumber } = require('ethers');
const { deployContract, MockProvider, solidity } = require('ethereum-waffle');
const { ethers, upgrades } = require("hardhat");

use(solidity);

describe("Test NFTSwap.sell Interface", function () {
    var ERC20;
    var ERC721;
    var ERC1155;
    var OWNER;
    var ADDR1;
    var NFT_SWAP;

    beforeEach(async () => {
        [OWNER, ADDR1] = await ethers.getSigners();

        const ERC20PresetMinterPauser = await ethers.getContractFactory("ERC20PresetMinterPauser", OWNER);
        ERC20 = await ERC20PresetMinterPauser.deploy("TestERC20", "T20");

        const ERC721PresetMinterPauserAutoId = await ethers.getContractFactory("ERC721PresetMinterPauserAutoId", OWNER);
        ERC721 = await ERC721PresetMinterPauserAutoId.deploy("TestERC721", "T721", "https://t721.com");

        const ERC1155PresetMinterPauser = await ethers.getContractFactory("ERC1155PresetMinterPauser", OWNER);
        ERC1155 = await ERC1155PresetMinterPauser.deploy("https://t1155.com");

        const NFTSwap = await ethers.getContractFactory("NFTSwap");
        NFT_SWAP = await upgrades.deployProxy(NFTSwap, {
            initializer: '__NFTSwap_init'
        });
    });


    it("Should be sale an ERC721 token successful", async function () {
        await NFT_SWAP.deployed();

        await ERC721.deployed();

        var mintERC721Tx = await ERC721.connect(OWNER).mint(OWNER.address);
        await mintERC721Tx.wait();
        var approveERC721Tx = await ERC721.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
        await approveERC721Tx.wait();

        var assets = [{ Contract: ERC721.address, TokenId: BigNumber.from(0), TokenValue: BigNumber.from(1), Type: 1 }]

        await ERC20.deployed();

        const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(1000000));
        await sellTx.wait()

        var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
        expect(receipt.status).to.equal(1);
    });

    it("Should be sale an ERC1155 token successful", async function () {
        await NFT_SWAP.deployed();

        await ERC1155.deployed();

        var mintERC1155Tx = await ERC1155.connect(OWNER).mint(OWNER.address, 1, 10, "0x");
        await mintERC1155Tx.wait();
        var approveERC1155Tx = await ERC1155.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
        await approveERC1155Tx.wait();

        var assets = [{ Contract: ERC1155.address, TokenId: BigNumber.from(1), TokenValue: BigNumber.from(1), Type: 2 }]

        await ERC20.deployed();
        const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(1000000));
        await sellTx.wait()

        var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
        expect(receipt.status).to.equal(1);
    });

    it("Should be packet sale an ERC721 token and an ERC1155 token successful", async function () {
        await NFT_SWAP.deployed();

        await ERC721.deployed();

        var mintERC721Tx = await ERC721.connect(OWNER).mint(OWNER.address);
        await mintERC721Tx.wait();
        var approveERC721Tx = await ERC721.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
        await approveERC721Tx.wait();

        await ERC1155.deployed();

        var mintERC1155Tx = await ERC1155.connect(OWNER).mint(OWNER.address, 1, 10, "0x");
        await mintERC1155Tx.wait();
        var approveERC1155Tx = await ERC1155.connect(OWNER).setApprovalForAll(NFT_SWAP.address, true);
        await approveERC1155Tx.wait();

        var assets = [{ Contract: ERC721.address, TokenId: BigNumber.from(0), TokenValue: BigNumber.from(1), Type: 1 },
        { Contract: ERC1155.address, TokenId: BigNumber.from(1), TokenValue: BigNumber.from(10), Type: 2 }]

        await ERC20.deployed();
        const sellTx = await NFT_SWAP.sell(assets, ERC20.address, BigNumber.from(200000));
        await sellTx.wait()

        var receipt = await ethers.provider.getTransactionReceipt(sellTx.hash);
        expect(receipt.status).to.equal(1);
    });
});

有问题,或者建议请留言,谢谢。文章来源地址https://www.toymoban.com/news/detail-784931.html

到了这里,关于基于Hardhat编写合约测试用例的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 8.区块链系列之hardhat框架部署合约(二)

    现在我们来实践hardhat部署合约中的其他更多技术要点 1. 代码方式验证合约 注册 https://etherscan.io/ , 如下图添加拷贝API_KEY 在.env文件中新增 ETHERSCAN_API_KEY hardhat.config.js中新增配置 覆盖deploy.js 验证合约 如果用的使用了clash代理的话开启Tun模式,否则可能会报Connect Timeout Error 2.

    2024年01月22日
    浏览(33)
  • 10.区块链系列之hardhat部署抵押赎回Fund合约

    本文继续通过笔者学习到的抵押赎回智能合约Fund来进一步学习solidity语言,加深对开发的理解,其中通过storage节省gas是需要重点实践的,毕竟涉及到资产 代码已提交至https://gitee.com/SJshenjian/blockchain/tree/master/hardhat-fund-me-fcc 1. 依赖安装 若出现如下错误 在yarn.lock中ethereumjs-abi指

    2023年04月09日
    浏览(30)
  • 怎么快速定位bug?怎么编写测试用例?

    目录 01定位问题的重要性  02问题定位技巧 03初次怎么写用例 作为一名测试人员如果连常见的系统问题都不知道如何分析,频繁将前端人员问题指派给后端人员,后端人员问题指派给前端人员,那么在团队里你在开发中的地位显而易见 , 口碑、升值、加薪那应该是你遥不可

    2024年02月15日
    浏览(54)
  • 智能合约开发笔记-hardhat入门

    Hardhat是一个编译、部署、测试和调试以太坊应用的开发环境。 先安装nodejs环境; 然后打开命令行执行以下命令, 在项目目录pj_220509下安装hardhat环境: pj_220509目录下, 执行命令 npx hardhat  然后按提示安装相关的nodejs包,如下;完成安装; 装完后呀,可以在本地启动一个区块

    2023年04月11日
    浏览(38)
  • 简介智能合约开发框架-Hardhat

    ​ Hardhat是一个编译、部署、测试和调试以太坊应用的开发环境。 Hardhat内置了Hardhat网络,这是一个专为开发设计的本地以太坊网络。主要功能有Solidity调试,跟踪调用堆栈、 console.log() 和交易失败时的明确错误信息提示等。 node.js python 安装 安装中如果出现这样的报错 下载

    2024年02月16日
    浏览(42)
  • ChatGPT助力测试领域!探索人工智能编写测试用例的新前景

    简介 测试用例是测试人员的核心工作内容,是测试人员思想的“实现类”,其充分体现了测试的思路,可以为后续的测试行为提供指导,是测试人员了解业务的重要根据和质量之根本。如果测试用例设计得不完成,出现了遗漏,那么通常是会出现大家不想看到的后果,如漏测

    2024年04月28日
    浏览(51)
  • 接口测试用例怎么编写?给你一个最详细的模板要不要?

    目录 接口测试用例 总部用户同步接口 添加组织 添加用户 删除组织 删除用户 更新组织 更新用户 应用系统同步用户接口 根据组织编码获取用户 根据系统编码获取用户 构型数据的集成 获取构型数据接口 编制人 薛郝 审定人 时间 用例名称 添加组织 接口名称 urn:orgservice 项目

    2023年04月08日
    浏览(46)
  • 区块链智能合约测试框架Foundry技术指南

    在区块链开发领域,智能合约的安全性和可靠性至关重要。鉴于区块链的不可变性,智能合约中的任何错误都可能导致不可逆转的后果,包括重大的财务损失。这凸显了彻底测试的关键重要性。Foundry 是一种 Solidity 测试框架,在这一领域中成为一个强大的工具,为开发人员提

    2024年02月03日
    浏览(56)
  • 基于openzeppelin编写solidity可升级的智能合约

            现代软件的设计原则是“敏捷开发,迅速迭代”,功能升级或bug修复是所有软件系统都要面对的问题。甚至可以说软件质量在很大程度上依赖于升级和修补源代码的能力。当然Dapp(去中心化应用)也不例外,尤其Dapp一切都是透明的,这使得任何级别的bug都会被成

    2024年01月18日
    浏览(48)
  • 基于区块链智能合约的疫苗溯源系统

    该系统基于以太坊的Solidity进行智能合约开发,并通过hardhat进行部署在了本机,通过Mocha和Chai进行了单元测试的编写,同时提供了一个基于React的前端界面与用户进行交互。 区块链的介绍 不难看出,区块链技术对现有的经济社会产生了巨大的影响。在未来,将会出现越来越多

    2024年02月15日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包