DApp 개발

Unit Test 환경구축 1

Remix로 테스트하면 되지 왜 별도의 테스트 환경을 구축하는지 의아해할 수 있습니다. 코딩한 컨트랙트를 보다 체계적으로 테스트하고, 테스트를 자동으로 하는 것은 코딩에 필수작업입니다. 그러나 개발자들이 종종 테스트를 철저히 하지 않는 경우가 있습니다. 여기서는 코딩에 반드시 필요한 테스트 환경을 구축하는 것을 알아보겠습니다.

개발환경은 리눅스(우분투) 16.04입니다. 윈도우즈와 조금 차이 있을수 있지만 큰 흐름은 같습니다.

  • 스마트 컨트랙트를 자동으로 컴파일하는 코드 작성
  • 컴파일 결과 Bytecode와 ABI 얻어짐
  • Bytecode를 이용하여 컨트랙트를 로컬 테스트 네트워크에 Deploy
  • ABI와 Web3를 이용하여 deploy된 컨트랙트의 내용 접근하여 기능 테스트 진행

1. npm 설정

npm은 자바스크립트 프로그래밍 모듈 관리자입니다. 특히 Node.js 개발환경의 기본 모듈 관리자입니다. 자세한 내용은 구글링을 해보세요. npm이 설치 안되어 있다면 설치를 하셔야 합니다.

$ curl -sL https://deb.nodesource.com/setup_9.x | sudo -E bash -
$ sudo apt-get install nodejs
$ sudo apt-get install build-essential

자세한 내용은 다음 사이트를 참고하세요.
https://twpower.github.io/100-install-nodejs-on-ubuntu

1. npm init

  • 프로젝트 디렉토리의 최상위에서 아래와 같이 입력
$ npm init

실행하면 아래와 같이 몇가지 물어보는게 그냥 엔터만 칩니다. 그러면 설정이 맞냐고 최종적으로 물어보는 메시지가 나오는데 다시한번 엔터치면 패키지관련 파일인 package.json파일이 생깁니다.

1.2 npm 패키지 인스톨

테스트를 진행하기 위해서는 다음과 같은 npm 패키지들이 필요합니다.

  • ganache-cli: 로컬 이더리움 테스트 네트워크
  • mocha: 테스트 프레임워크
  • solc: 솔리디티 컴파일러
  • fs-extra: 파일 시스템 확장 기능
  • web3@1.0.0-beta.26: web3. 버전이 빠르게 업데이트 되어, 동일한 환경을 맞추기 위함
$ npm install --save ganache-cli mocha solc fs-extra web3@1.0.0-beta.26

위 명령에 사용된 옵션 --save는 설치하는 모듈을 package.json파일에 저장하라는 의미입니다.

패키지 설치가 끝나면 아래와 같이 node_modules이라는 것이 생깁니다. 참고로, 저는 대략적인 디렉터리 구성을 해놓은 상태라 조금 다르게 보일 것입니다. node_modules에 위에서 설치한 모듈이 있어야 합니다. 위에 설치한 것 이외에 의존되는 모듈들이 많이 보일 것입니다.

2. 디텍터리 구성

컨트랙트 소스 파일과 테스트 파일, 웹페이지 파일(향후 추가) 등을 적절한 디렉터리로 구분해 주면 깔끔합니다. 아래와 같은 구조를 추천합니다.

compile.js, deploy.js, web3.js등은 아직 설명을 안했지만, 위와 같은 구조에 잡아놓으면 좋습니다. 그리고 편의상 node_modules은 표시하지 않았습니다.

3. 자동 컴파일 스크립트 만들기

스마트 컨트랙트를 테스트 프로그램이 자동으로 하려면 컨트랙트 컴파일을 자동으로 할 수 있어야 합니다. 이를 위해 다음과 같은 스크립트를 구성합니다.

  • 파일이름: compile.js
  • 파일위치: 위 디렉터리 구조 참고
// @note: this compile.js will be usually executed once unless the contract file is changed.
// path module to read soliditi files
const path= require('path');
// solidity compiler module
const solc= require('solc');
// file system extra functionality
const fs= require('fs-extra');

// get the build directory using the path module
// build directory is used to re-use the compiled code when no change occurs
// __dirname will indicate the root directory where the oxmpile.js occurs
const build_path= path.resolve( __dirname, 'build' );
// delete the build directory
fs.removeSync( build_path );

// get the contract file path
const contract_path= path.resolve( __dirname, 'contracts', 'DreamStory.sol' );
// read the contract file
const contract_src= fs.readFileSync( contract_path, 'utf8' );
// compiled output, extract only contracts part
const compile_output= solc.compile( contract_src, 1 ).contracts;
// create the build directory
fs.ensureDirSync( build_path );

// create build files looping over contracts
for( let contract in compile_output ) {
  // create a contract json file
  fs.outputJsonSync(
    path.resolve( build_path, contract.replace(':', '') + '.json' ),
    compile_output[ contract ]
  );
}

위 코드의 주요 기능은 컨트랙트 파일이 변경되면 build 디렉터리를 지우고, 새로 컴파일해서 그 결과중에 contracts 부분만 추출하여 build 디렉터리 밑의 별도의 json 파일을 만듭니다. 주의깊게 볼 점은 이 compile.js 파일은 컨트랙트 내용이 변경되지 않으면 다시 실행되지 않습니다. 컨트랙트의 내용에 대해 unit test 진행할 때, 매번 컴파일을 하지 않아 빠릅니다.

참고로, 위 코드에서 한 파일에 컨트랙트가 여러 개일 경우에 컴파일 결과를 컨트랙트별로 별도의 파일로 저장합니다. 나중에 컨트랙트를 하나 추가할 것이기 때문에 복수의 컨트랙트가 존재하는 상황에 맞도록 코딩했습니다.

컴파일 스크립트 실행

그러면 컴파일 스크립트를 실행해 보겠습니다. 아래와 같이 compile.js가 있는 폴더로 이동한 후 스크립트를 실행합니다.

$ cd ethereum
$ node compile.js

문제없이 컴파일이 되면 ethereum/build 폴더 밑에 DreamStory.json 파일이 생길 것입니다.


체력이 딸려서 deploy하는 스크립트는 다음에 이어서 하겠습니다. 환경구축하는데 분량도 좀 늘어난거 같구요. 테스트 환경 구축은 매우 중요합니다. 개발을 더욱 효율적으로 하게 하고, 발생할 수 있는 오류를 최소로 줄여주기 때문입니다. 테스트 환경을 구축하고, 테스트를 한다고 코딩 시간이 결코 늘어나는게 아닙니다. 테스트로 코딩 시간을 단축시키는 것입니다. 어디선가 오류가 발생하면 그거 잡아내기 전까지는 코드가 완성되었다고 얘기할 수 없겠죠!


오늘의 실습: 코딩할 때 테스트를 하면 좋은 점을 찾아보세요.

댓글

댓글 본문
graphittie 자세히 보기