🌊

NFTを発行するSmart Contractのテスト(chai & mocha)で使える書き方

2022/12/20に公開

NFTを発行するSmart Contractのテストで使える書き方をまとめてみました。
Hardhatでchai&mochaを使っていることを想定しています。

書き方

loadFixtureを使って毎回デプロイしないようにする

一番シンプルに書くと各テストでdeployをすることになると思うんですが、テストが増えてくると実行時間的にもあまり良くない状態になってくるのでfixtureとして読み込むようにすると良いと思います。

  async function deployContractFixture() {
    // Sampleはコントラクト名に書き換えてください
    const Contract = await ethers.getContractFactory("Sample");
    const [owner, addr1, addr2] = await ethers.getSigners();

    const hardhatContract = await Contract.deploy();
    await hardhatContract.deployed();

    return { Contract, hardhatContract, owner, addr1, addr2 };
  }

  describe("Deployment", function () {
    it("Should deploy", async function () {
      const { hardhatContract, owner } = await loadFixture(
        deployContractFixture
      );
      expect(await hardhatContract.owner()).to.equal(owner.address);
    });
  });

現在時間を設定する

HardhatネットワークのJSON-RPCを呼び出せます。

  async function setTime(datetime: number) {
    await ethers.provider.send("evm_mine", [datetime]);
  }

Hardhat ネットワークを扱うHelperを利用するやり方が良さそうなのですが私はなぜか動かなかったです。
https://hardhat.org/hardhat-network-helpers/docs/overview

参考: https://ethereum.stackexchange.com/questions/86633/time-dependent-tests-with-hardhat

mint価格のチェック

無料ではない場合、正しいvalueになっているかチェックが必要です。
こういう関数を想定しています。

  uint256 public price = 10000000000000000;
  
  function mint(address toAddress, uint256 amount) external payable {
    require(msg.value == price * amount, "Incorrect payment value");
    _mint(toAddress, 1, amount, "");
  }

etherjsでは呼び出す関数の最後にoverride用の情報を加えることができます。
https://docs.ethers.org/v5/api/contract/contract/#contract-functionsSend
なのでこんな感じでかけます。

const { hardhatContract, addr1 } = await loadFixture(
deployContractFixture
);
const mintTx = await Contract
  .connect(addr1)
  .mint(addr1.address, 1, {
    value: ethers.utils.parseEther("0.1")
  });

mint関数を呼んだユーザー以外にmintされていることを確認

mint関数を呼んだユーザー、signerではないユーザーにmintされていることを確認したい場合もoverrideで書けます。
今回もこんな感じのコードを用意します。

  uint256 public price = 10000000000000000;
  
  function mint(address toAddress, uint256 amount) external payable {
    require(msg.value == price * amount, "Incorrect payment value");
    _mint(toAddress, 1, amount, "");
  }

今回はtoを指定しましょう。

const { hardhatContract, addr1, addr2 } = await loadFixture(
deployContractFixture
);
const mintTx = await Contract
  .connect(addr1)
  .mint(addr1.address, 1, {
    to: addr2.address
  });

基本的には変更ができないSmart Contractはテストが大事です。
お役に立てば幸いです。

参考

https://hardhat.org/tutorial/testing-contracts#full-coverage

Discussion