일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- rust 기초
- Vue
- ambiguous function description
- 스마트 컨트렉트 함수이름 중복
- ethers websocket
- 컨트렉트 동일한 함수이름 호출
- 러스트기초
- 티스토리챌린지
- 체인의정석
- 스마트컨트렉트 함수이름 중복 호출
- ethers
- 스마트컨트렉트 예약어 함수이름 중복
- erc4337 contract
- Vue.js
- ethers typescript
- 러스트 기초 학습
- git rebase
- chainlink 설명
- ethers v6
- 계정추상화
- 스마트컨트렉트테스트
- 러스트 기초
- 오블완
- vue기초
- 머신러닝기초
- SBT표준
- multicall
- erc4337
- 컨트렉트 배포 자동화
- ethers type
- Today
- Total
체인의정석
hardhat 사용법 정리 03- 테스트코드 작성하기 본문
이제 배포를 했으니 테스트코드를 작성하고 돌려봐야 한다.
테스트 코드는 딱히 가나슈랑 다른 점은 없어보여서 그대로 가져와서 사용해보기로하였다.
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Greeter", function () {
it("Should return the new greeting once it's changed", async function () {
const Greeter = await ethers.getContractFactory("Greeter");
const greeter = await Greeter.deploy("Hello, world!");
await greeter.deployed();
expect(await greeter.greet()).to.equal("Hello, world!");
const setGreetingTx = await greeter.setGreeting("Hola, mundo!");
// wait until the transaction is mined
await setGreetingTx.wait();
expect(await greeter.greet()).to.equal("Hola, mundo!");
});
});
chai 모듈과 ethers를 사용하여 테스트를 하는것인데 나도 이대로 하려고 한다.
expect를 걸어두는 부분이나 함수를 변수화하여 비동기화 시키는 작업이 필요한것 같다.
https://docs.openzeppelin.com/test-helpers/0.5/
Test Helpers - OpenZeppelin Docs
Assertion library for Ethereum smart contract testing. Make sure your contracts behave as expected!
docs.openzeppelin.com
오픈제플린의 공식 ERC 코드를 살펴보다가 test helper라는 모듈을 사용하고 있음을 발견하였다.
https://docs.openzeppelin.com/test-environment/0.1/
Test Environment - OpenZeppelin Docs
Blazing fast smart contract testing. One-line setup for an awesome testing experience. Near-instant start up: have your code running in under 2s after typing npm test. Test runner agnostic – from the familiarity of Mocha, to parallel tests using Jest or
docs.openzeppelin.com
또한 테스트 환경에 대한 모듈도 사용이 가능하다.
그러나 트러플과 하드햇의 환경이 혼동되어서 문서를 찾아보니 깔끔하게 정리된 페이지가 있었다.
위 3개의 페이지를 참고하여 테스트코드를 작성할 예정이다.
https://docs.openzeppelin.com/learn/writing-automated-tests?pref=hardhat
Writing automated smart contract tests - OpenZeppelin Docs
You may be wondering how we’re going to run these tests, since smart contracts are executed inside a blockchain. Using the actual Ethereum network would be very expensive, and while testnets are free, they are also slow (with blocktimes between 5 and 20
docs.openzeppelin.com
먼저 chai를 테스트 모듈로 사용한다.
npm install --save-dev chai
test 디렉토리에 테스트 코드를 관리하게 되는데 contracts 디렉토리에 있는 것을 미러링 하여 테스트 디렉토리에 그대로 넣어 주어야 한다. test 디렉토리는 루트 경로에 있어야 하며 .js 파일 형태로 만든다.
// test/Box.test.js
// Load dependencies
const { expect } = require('chai');
// Start test block
describe('Box', function () {
before(async function () {
this.Box = await ethers.getContractFactory('Box');
});
beforeEach(async function () {
this.box = await this.Box.deploy();
await this.box.deployed();
});
// Test case
it('retrieve returns a value previously stored', async function () {
// Store a value
await this.box.store(42);
// Test if the returned value is the same one
// Note that we need to use strings to compare the 256 bit integers
expect((await this.box.retrieve()).toString()).to.equal('42');
});
});
이런 식으로 테스트 코드를 작성하면 되는데, 아래 링크를 공부해보라고 나와있었다.
GitHub - MolochVentures/moloch: 👹 Moloch whose mind is pure machinery! Moloch whose blood is running money!
👹 Moloch whose mind is pure machinery! Moloch whose blood is running money! - GitHub - MolochVentures/moloch: 👹 Moloch whose mind is pure machinery! Moloch whose blood is running money!
github.com
여기 글을 보면 반복되는 부분에 대해서 EVM snapshot과 revert를 사용하여 테스트를 빠르게 하며 반복을 줄인다고 한다.
beforeEach(async () => {
snapshotId = await snapshot()
proposal1 = {
applicant: applicant1,
tokenTribute: 100,
sharesRequested: 1,
details: 'all hail moloch'
}
token.transfer(summoner, initSummonerBalance, { from: creator })
})
afterEach(async () => {
await restore(snapshotId)
})
테스트 코드에 자꾸 beforeEach가 나와 있는데 이러한 부분은 각 유닛테스트시 작동하게 된다. afterEach는 유닛테스트 이후에 작동하게 된다. 위의 코드에서 beforeEach를 사용하여 글로벌 변수들을 예측 가능한기본선으로 세팅해주게 된다. 이러한 each 구문은 describe의 블록 범위 앞뒤에서 트리거가 되게 된다. 또한 더 높은 스코프에서의 Each는 해당 범위를 모두 포괄하여 작동하게 된다.
foreEach_1 -> beforeEach_2 -> { test } -> afterEach
describe('submitProposal', () => {
beforeEach(async () => {
await token.transfer(proposal1.applicant, proposal1.tokenTribute, {
from: creator
})
await token.approve(moloch.address, 10, { from: summoner })
await token.approve(moloch.address, proposal1.tokenTribute, {
from: proposal1.applicant
})
})
beforeEach는 submitProposal의 단위 테스트를 위하여 토큰을 보내고 어프루브를 받아서 디파짓이 매번 가능하도록 만들어 준다.
이렇게 반복되는 기능은 매 테스트마다 계속해서 사용하게 된다.
it('happy case', async () => {
await moloch.submitProposal(
proposal1.applicant,
proposal1.tokenTribute,
proposal1.sharesRequested,
proposal1.details,
{ from: summoner }
)
await verifySubmitProposal(proposal1, 0, summoner, {
initialTotalShares: 1,
initialApplicantBalance: proposal1.tokenTribute,
initialProposerBalance: initSummonerBalance
})
})
위의 테스트가 있다고 쳐보고
it('require fail - uint overflow', async () => {
proposal1.sharesRequested = _1e18
await moloch
.submitProposal(
proposal1.applicant,
proposal1.tokenTribute,
proposal1.sharesRequested,
proposal1.details,
{ from: summoner }
)
.should.be.rejectedWith('too many shares requested')
})
아래의 테스트가 반복되는 경우 단 하나만 바뀌게 된다. 오버 플로우를 테스트하기 위해 이처럼 반복되는 코드가 많이 나오게 된다.
이런 부분을 해결하기 위해 before Each를 달아서 중복되는 부분을 한번에 처리할 수 있다.
이번 부분은 중요하기 때문에 다음 글에서 이어서 정리하도록 하겠다.
'블록체인 > Ethers & web3' 카테고리의 다른 글
ethers.js에서 keccak256 사용하기 (0) | 2022.02.13 |
---|---|
ether.js에서 HexPad 하기 (0) | 2022.02.11 |
hardhat 오류 해결) bytes32 형태의 값 넣는 방법 (0) | 2022.01.27 |
hardhat 사용법 정리 04- 테스트코드 작성하기 2 (0) | 2022.01.19 |
hardhat 사용법 정리 01- 하드햇 설치 및 기본세팅 진행 (0) | 2022.01.17 |