# 智能合約測試 [TOC] ###### tags: `Dapp` `區塊鏈` ---- ## Unit Test(單元測試) * [TDD BDD](https://medium.com/@envive.tw/%E5%89%8D%E8%A8%80-%E6%9A%B4%E8%B5%B0gandhi-%E4%B8%8D%E7%9F%A5%E9%81%93%E5%A4%A7%E5%AE%B6%E6%9C%89%E6%B2%92%E6%9C%89%E7%8E%A9%E9%81%8E%E4%B8%80%E6%AC%BE%E9%81%8A%E6%88%B2%E5%8F%AB%E5%81%9A-civilization-%E6%96%87%E6%98%8E%E5%B8%9D%E5%9C%8B-441891b116d7) * [JavaScript 用 Jest 做單元測試](https://nicolakacha.coderbridge.io/2020/09/05/jest/) * TDD (Test-driven Development) 測試驅動開發:先測試再開發 ![](https://i.imgur.com/dn0icjX.png) * Unit Test種類 * Mocha+Chai * [Mocha documentation](https://mochajs.org/) * Jest ![](https://i.imgur.com/L75Bpv0.png =x400) * [智能合約jest 測試](https://blog.gasolin.idv.tw/2018/01/02/howto-write-a-contract-test/) ---- ## Truffle Test ``` javacript= const CryptoZombies = artifacts.require("CryptoZombies"); contract("CryptoZombies", (accounts) => {//"CrptoZombies"--->智能合約名字 callback--->accounts:要寫test的地方 it("should be able to create a new zombie", () => { })//"should be able to receive Ethers"--->the name of our test }) ``` --- ``` javacript= const CryptoZombies = artifacts.require("CryptoZombies"); const zombieNames = ["Zombie 1", "Zombie 2"]; contract("CryptoZombies", (accounts) => { let [alice, bob] = accounts; it("should be able to create a new zombie", async () => { const contractInstance = await CryptoZombies.new(); //async }) //connect to blockchain ``` ``` javacript= const result = await contractInstance.createRandomZombie(zombieNames[0], {from: alice}); ``` ``` javacript= const CryptoZombies = artifacts.require("CryptoZombies"); const zombieNames = ["Zombie 1", "Zombie 2"]; contract("CryptoZombies", (accounts) => { let [alice, bob] = accounts; it("should be able to create a new zombie", async () => { const contractInstance = await CryptoZombies.new(); const result = await contractInstance.createRandomZombie(zombieNames[0],{from:alice}); assert.equal(result.receipt.status,true); assert.equal(result.logs[0].args.name,zombieNames[0]); }) }) ``` * 用 ==artifacts.require()== 來指定我們要test的smart contract(名字叫"CryptoZombies") * Truffle會自動提供smart contract產生的logs * result.logs[0].args.name--->第一個產生的cryptozombies名字 * result.logs[0].args.id--->第一個產生cryptozombies id * result.logs[0].args._dna--->第一個產生cryptozombies _dna * result.tx: the transaction hash * result.receipt: an object containing the transaction receipt. * result.receipt()==true--->trasaction成功 * result.receipt()==false--->transaction失敗 * logs為store data較便宜的選擇,但 logs 不能從 smart contract 中 access * [module.export用法](https://ithelp.ithome.com.tw/articles/10185083) * [Node.js 的 module.exports 和 require ](https://dwatow.github.io/2018/02-13-js-module-require-exports/) ---- ### assert #### equal() * assert.equal() #### deepEqual()深層比對 * assert.deepEqual() #### toEqual深層比對 * toEqual 是屬於深度比對(deep equality) * ex: expect(block.data).toEqual(data); --- ### contract Instance ``` javacript= const CryptoZombies = artifacts.require("CryptoZombies"); const zombieNames = ["Zombie 1", "Zombie 2"]; contract("CryptoZombies", (accounts) => { let [alice, bob] = accounts; it("should be able to create a new zombie", async () => { const contractInstance = await CryptoZombies.new(); const result = await contractInstance.createRandomZombie(zombieNames[0], {from: alice}); // 確定msg.sender為alice assert.equal(result.receipt.status, true); assert.equal(result.logs[0].args.name,zombieNames[0]); }) }) ``` * 程式例子2---> ``` javacript= const CryptoZombies = artifacts.require("CryptoZombies"); const zombieNames = ["Zombie 1", "Zombie 2"]; contract("CryptoZombies", (accounts) => { let [alice, bob] = accounts; let contractInstance; beforeEach(async () => { contractInstance = await CryptoZombies.new();// let's put here the code that creates a new contract instance }); it("should be able to create a new zombie", async () => { const contractInstance = await CryptoZombies.new(); const result = await contractInstance.createRandomZombie(zombieNames[0], {from: alice}); assert.equal(result.receipt.status, true); assert.equal(result.logs[0].args.name,zombieNames[0]); }) it("should not allow two zombies", async () =>{ }) }) ``` ### selfdestruct ``` javascript= function kill() public onlyOwner { selfdestruct(owner());//唯一可以將blockchain上的code銷毀方法銷毀合約 } ``` #### Test 被 execute 後 , 會確保有將 智能合約 kill ``` javascript= afterEach(async () => { await contractInstance.kill(); }); ``` ---- ![](https://i.imgur.com/trctR67.png) ![](https://i.imgur.com/WM58Vnk.png) ---- #### # 智能合約開發審計 * [智能合約開發的最佳實踐 - 強烈推薦](https://www.chainnews.com/zh-hant/articles/938555591102.htm)