---
# System prepended metadata

title: 智能合約測試
tags: [區塊鏈, Dapp]

---

# 智能合約測試 

[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)