見出し画像

Hardhat入門⑤-4(コントラクトのテスト) ~ブロックチェーンエンジニアになろう~

さて、テストもおそらく今日でラストです。

いつものようにHardhat公式です。

さて、ではHardhat公式のこちらのテストコードを見ていきましょう。(な、長い)全部はやらずにピックアップして見ていきますね。

// We import Chai to use its asserting functions here.
const { expect } = require("chai");
// `describe` is a Mocha function that allows you to organize your tests. It's
// not actually needed, but having your tests organized makes debugging them
// easier. All Mocha functions are available in the global scope.
// `describe` receives the name of a section of your test suite, and a callback.
// The callback must define the tests of that section. This callback can't be
// an async function.

describe("Token contract", function () {
 // Mocha has four functions that let you hook into the the test runner's
 // lifecyle. These are: `before`, `beforeEach`, `after`, `afterEach`.
 // They're very useful to setup the environment for tests, and to clean it
 // up after they run.
 // A common pattern is to declare some variables, and assign them in the
 // `before` and `beforeEach` callbacks.
 let Token;
 let hardhatToken;
 let owner;
 let addr1;
 let addr2;
 let addrs;
 // `beforeEach` will run before each test, re-deploying the contract every
 // time. It receives a callback, which can be async.
 
 beforeEach(async function () {
   // Get the ContractFactory and Signers here.
   Token = await ethers.getContractFactory("Token");
   [owner, addr1, addr2, ...addrs] = await ethers.getSigners();
   // To deploy our contract, we just have to call Token.deploy() and await
   // for it to be deployed(), which happens once its transaction has been
   // mined.
   hardhatToken = await Token.deploy();
 });
 // You can nest describe calls to create subsections.
 
 describe("Deployment", function () {
   // `it` is another Mocha function. This is the one you use to define your
   // tests. It receives the test name, and a callback function.
   // If the callback function is async, Mocha will `await` it.
   
   it("Should set the right owner", async function () {
     // Expect receives a value, and wraps it in an Assertion object. These
     // objects have a lot of utility methods to assert values.
     // This test expects the owner variable stored in the contract to be equal
     // to our Signer's owner.
     expect(await hardhatToken.owner()).to.equal(owner.address);
   });
   
   it("Should assign the total supply of tokens to the owner", async function () {
     const ownerBalance = await hardhatToken.balanceOf(owner.address);
     expect(await hardhatToken.totalSupply()).to.equal(ownerBalance);
   });
 });
 
 describe("Transactions", function () {
   
   it("Should transfer tokens between accounts", async function () {
     // Transfer 50 tokens from owner to addr1
     await hardhatToken.transfer(addr1.address, 50);
     const addr1Balance = await hardhatToken.balanceOf(addr1.address);
     expect(addr1Balance).to.equal(50);
     // Transfer 50 tokens from addr1 to addr2
     // We use .connect(signer) to send a transaction from another account
     await hardhatToken.connect(addr1).transfer(addr2.address, 50);
     const addr2Balance = await hardhatToken.balanceOf(addr2.address);
     expect(addr2Balance).to.equal(50);
   });
   
   it("Should fail if sender doesn’t have enough tokens", async function () {
     const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);
     // Try to send 1 token from addr1 (0 tokens) to owner (1000000 tokens).
     // `require` will evaluate false and revert the transaction.
     await expect(
       hardhatToken.connect(addr1).transfer(owner.address, 1)
     ).to.be.revertedWith("Not enough tokens");
     // Owner balance shouldn't have changed.
     expect(await hardhatToken.balanceOf(owner.address)).to.equal(
       initialOwnerBalance
     );
   });
   
   it("Should update balances after transfers", async function () {
     const initialOwnerBalance = await hardhatToken.balanceOf(owner.address);
     // Transfer 100 tokens from owner to addr1.
     await hardhatToken.transfer(addr1.address, 100);
     // Transfer another 50 tokens from owner to addr2.
     await hardhatToken.transfer(addr2.address, 50);
     // Check balances.
     const finalOwnerBalance = await hardhatToken.balanceOf(owner.address);
     expect(finalOwnerBalance).to.equal(initialOwnerBalance - 150);
     const addr1Balance = await hardhatToken.balanceOf(addr1.address);
     expect(addr1Balance).to.equal(100);
     const addr2Balance = await hardhatToken.balanceOf(addr2.address);
     expect(addr2Balance).to.equal(50);
   });
 });
});

まず、今回初めて出ました「beforeEach」についてみてみましょう。

ざっくりとこんな関係性です。

beforeEachはその名の通り、それぞれの前の処理です。

この後にdescribeが2つ書かれていますが、それぞれを実行する前にこのbeforeEachをやってね。という部分になります。

beforeEach(async function () {
   あーだこーだ
 });
 
 
 describe("Deployment", function () {
   あーだこーだ   
 });
 
 describe("Transactions", function () {
   あーだこーだ
   
 });

次に今回新しく出てきたのはこちらでしょうか。

今、状況としては「addr1」にはトークンがないのに「owner」にトークンを送ろうとしています。

普通に考えて送れないですよね。

ただ、その普通に送れないということだきちんとできるかのテストをする必要があります。

実は持っているトークンより送ろうとしているトークンの方が多いと「"Not enough tokens"」という文言が返されることをコントラクトに書き込んでいました。(第4章)

await expect(
       hardhatToken.connect(addr1).transfer(owner.address, 1)
     ).to.be.revertedWith("Not enough tokens");

なので今回は

返ってきた文言があっているかを

be.revertedWith("Not enough tokens")

で確認していたのですね。

あとは、、、あ、もう新しいことはなさそうです。

内容的には前回、前々回あたりでカバーできていそうです。

ぜひぜひ、みなさん自身でも解読してみてくださいね。

最後に補足情報が載っていました。

テスト実行前にsolidityのコードが変更したときは自動でコンパイルが行われるよということが書いてありました。

ということはテストをする時には、必ず最新の状態のコントラクトでテストをしているということが担保されているのですね。

これはとても便利。

今回は以上にしたいと思います。

最後までお読みいただき、ありがとうございました。


サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊