# 智能合約測試
[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) 測試驅動開發:先測試再開發

* Unit Test種類
* Mocha+Chai
* [Mocha documentation](https://mochajs.org/)
* Jest

* [智能合約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://www.chainnews.com/zh-hant/articles/938555591102.htm)