-
[SmartContract] Truffle μμ Solidity Test Code μμ±νκΈ°SECURITY/Blockchain 2022. 1. 21. 15:35
μ΄λ²μλ truffle νλ‘μ νΈμμ solidity μ½λμ λν test code μμ±νλ λ°©λ²μ μμλ³΄κ² μ΅λλ€.
λ¨μ ν μ€νΈλ javascript λλ solidity λ‘ ν μ€νΈ μ€ν¬λ¦½νΈλ₯Ό μμ±νλ©΄ λ©λλ€.
μλ°μ€ν¬λ¦½νΈμ κ²½μ°, μλ°μ€ν¬λ¦½νΈ ν μ€νΈ νλ μμν¬μΈ mocha λ₯Ό κΈ°λ°μΌλ‘ ν©λλ€.
νΈλ¬νλ‘ ν μ€νΈλ₯Ό μμ±νλ©΄, contract λ₯Ό μ»΄νμΌνκ³ μλμΌλ‘ λ°°ν¬ν νμ μμ΄ migration μΌλ‘ λ°°ν¬λ 컨νΈλνΈλ₯Ό μ°Έμ‘°ν μ μκ³ , μ΄λ리μ μ£Όμλ₯Ό νλμ½λ©νμ§ μκ³ μμμ μΌλ‘ κ³μ μ μ°Έμ‘°ν μ μμ΅λλ€.
solidity λ‘ ν μ€νΈ μ€ν¬λ¦½νΈλ₯Ό μμ±νλ κ²μ λ³΄λ€ μ¬νμ μΈ λ΄μ©μ΄λΌ, μ΄ ν¬μ€ν μμλ μλ°μ€ν¬λ¦½νΈλ‘ μμ±νλ κ²μ ν΄λ³΄λλ‘ νκ² μ΅λλ€.
1) solidity μ½λ μμ±νκΈ°
ν μ€νΈλ₯Ό μν΄ HelloWorld Contract λ₯Ό λ€μκ³Ό κ°μ΄ μμ±ν΄μ£Όμμ΅λλ€. (/contracts/HelloWorld.sol)
pragma solidity >=0.7.0 <0.9.0; contract HelloWorld { string public greet = "Hello World!"; function echo(string memory _input) external pure returns (string memory){ return _input; } }
greet λ©μμ§κ° μκ³ , echo ν¨μκ° μλ κ°λ¨ν contract μ λλ€.
migration λ μμ±ν΄μ€λλ€. (/migrations/2_HelloWorld_migration.js)
const HelloWorld = artifacts.require("HelloWorld"); module.exports = function (deployer) { deployer.deploy(HelloWorld); };
2) test script μμ±
ν μ€νΈ μ½λλ truffle νλ‘μ νΈμ test ν΄λμ μμΉν΄μΌ ν©λλ€.
λλΆλΆ λΉλκΈ°λ‘ λμνλ―λ‘, κ²°κ³Όλ₯Ό assert νλ λΆλΆλ λΉλκΈ°μ μΌλ‘ μμ±ν΄μΌ ν©λλ€ (Promise, async/await).
μ λΉλκΈ°λ νλ©΄μ, λΈλ‘μ²΄μΈ λ€νΈμν¬μ λ°°ν¬λκ³ block μ΄ μμ±λλ λ°μλ μ§μ° μκ°μ΄ λ°μνκΈ° λλ¬Έμ λλ€.
λ°λΌμ λ‘컬 ν μ€νΈλ·μ μ΄μ©νμ λ μ§μ°μκ° μμ΄ λμμν€λ©΄ λΉλκΈ°λ‘ μΈν μ€λ₯κ° λ°μνμ§ μμ μ μμ΄λ―λ‘, μ€μ νκ²½μμμ λμλ κ³ λ €νλ€λ©΄ μ§μ°μκ°μ μ€μ νμ¬ (ganache μμ μ€μ κ°λ₯) ν μ€νΈν΄λ³΄κΈ°λ₯Ό κΆμ₯ν©λλ€.
λ¨Όμ greet λ©μμ§μ λν ν μ€νΈλ‘ ν μ€νΈ μ½λμ ꡬ쑰λ₯Ό μ΄ν΄λ³΄λλ‘ νκ² μ΅λλ€. (/test/HelloWorldTest.js)
var hello = artifacts.require("HelloWorld") contract("HelloWorld", function () { it ("is_greet_works_well", async function () { const instance = await hello.deployed(); const response = await instance.greet(); assert.equal(response, "Hello World", "greeting message is wrong"); }) })
- var hello = artifacts.require("HelloWorld"): HelloWorld contract λ₯Ό κ°μ Έμ΅λλ€.
- contract(): 컨νΈλνΈλ₯Ό λ°°ν¬νκ³ ν μ€νΈλ₯Ό μ§νλ, 'λ¨μ ν μ€νΈ λ¬Άμ' μ λλ€. μ΄ λ΄λΆμμλ κ²°κ³Όκ° κ³΅μ λλ―λ‘ νμνλ€λ©΄ μμλ μ°κ΄ κ΄κ³λ₯Ό κ³ λ €ν΄μΌ ν©λλ€. contract() νΈμΆμ λͺ¨λ 컨νΈλνΈκ° μ΄λ리μ ν΄λΌμ΄μΈνΈμ λ€μ λ°°ν¬νλ κ²μΌλ‘, κΉ¨λν μνμμ ν μ€νΈλ₯Ό μ§νν μ μλλ‘ ν©λλ€. λν, κΈ°λ³Έμ μΌλ‘ account[0] λ‘ contract λ₯Ό λ°°ν¬νκ² λ©λλ€.
- it(): νλμ ν μ€νΈ μ½λλ₯Ό μμν©λλ€.
- it ("is_greet_works_well", async function () {}: ν
μ€νΈ μ½λ λ©μμ§λ₯Ό μ μ΄μ£Όκ³ , ν΄λΉνλ ν¨μλ₯Ό μμ±ν΄μ€λλ€. promise λ¬Έλ²μ μ¬μ©ν΄λ λμ§λ§, μ¬κΈ°μλ async/await λ¬Έλ²μ μ¬μ©νκΈ° μν΄ async function μΌλ‘ μμ±ν΄μ£Όμμ΅λλ€. λν, νμ¬ HelloWorld 컨νΈλνΈλ μλ¬΄λ° μμ± parameter κ° μμΌλ―λ‘ μΈμλ₯Ό μμ±νμ§ μμμ΅λλ€.
(μ£Όμ: async/await λ₯Ό μ¬μ©νλ €λ©΄ Node.js λ²μ 8.0 μ΄μμμ μ€νν΄μΌ ν©λλ€) - const instance = await hello.deployed(): HelloWorld 컨νΈλνΈκ° λ°°ν¬λ instance λ₯Ό κ°μ Έμ΅λλ€.
- const response = await instance.greet(): greet λ₯Ό μ€ννκ³ λ°νκ°μ κ°μ Έμ΅λλ€. AAA λ μ΄μμ (Arrange, Act, Assert) μ Act μ ν΄λΉνλ λΆλΆμ λλ€.
- assert.equal(response, "Hello World!", "greeting message is wrong"): μμλλ‘ λΉκ΅ν 2κ°μ§ κ°, μ€ν¨ μ μΆλ ₯ν λ©μμ§λ₯Ό μ μ΄μ€λλ€. μ¬κΈ°μλ λ°νλ response μ 컨νΈλνΈμ greet μ λ£μ΄λ "Hello World!", κ·Έλ¦¬κ³ μ€ν¨ μ μΆλ ₯ν "greeting message is wrong" λ₯Ό λ£μ΄μ£Όμμ΅λλ€. AAA λ μ΄μμ (Arrange, Act, Assert) μ Assert μ ν΄λΉνλ λΆλΆμ λλ€.
echo() μ λν ν μ€νΈλ μ΄ν μ΄ν΄λ³΄κ² μ΅λλ€.
3) test
μ΄μ μμ±ν ν μ€νΈ μ½λλ₯Ό ν μ€νΈν΄λ³΄λλ‘ νκ² μ΅λλ€.
contract() μμλ μ μ μλ―μ΄, νΈλ¬νμ ν΄λ¦°λ£Έ ν μ€νΈλ₯Ό μ§μν©λλ€.
μ¦, ν μ€νΈ μ½λ μ€ν μ μ νμΌ λ€νΈμν¬μ λ§μ΄κ·Έλ μ΄μ μ μ€ννμ¬ μ»¨νΈλνΈλ₯Ό μ²μλΆν° λ€μ λ°°ν¬ν©λλ€.
λ°λΌμ κ°λ° μ€μλ ν μ€νΈ λ€νΈμν¬λ₯Ό μ€μ νμ¬ λ¨μ ν μ€νΈλ₯Ό μ€ννλ κ²μ΄ μ’κ³ , μ΅μ’ μΌλ‘λ νΌλΈλ¦ λ€νΈμν¬μμ ν μ€νΈλ₯Ό μ€ννλ κ²μ΄ μ’μ΅λλ€.
μ¬κΈ°μλ μ΄μ ν¬μ€ν μμ μ€μ ν development λ€νΈμν¬μμ μ€ννλλ‘ νκ² μ΅λλ€.
development λ κΈ°λ³Έ λ€νΈμν¬λ‘ μΈμνλ―λ‘ λ°λ‘ λͺ μνμ§ μμλ λμ§λ§, λ€μκ³Ό κ°μ΄ λͺ μνμ¬ μ¬μ©ν μ μμ΅λλ€.
$ truffle test $ truffle test --network development // network λͺ μ $ truffle test ./test/HelloWorldTest.js // νμΌ λͺ μ
νΉμ νμΌλ§ μ€ννκ³ μΆλ€λ©΄ κ²½λ‘λ₯Ό λͺ μνμ¬ μ€νμν¬ μ μμ΅λλ€.
ν μ€νΈλ₯Ό μ€νμν€λ©΄ λ¨Όμ solidity μ½λλ₯Ό μ»΄νμΌνκ³ ν μ€ν μ μ§νν©λλ€.
λ€μμ μμ μμ±ν ν μ€νΈ μ½λμ μ€ν κ²°κ³Όμ λλ€.
contract μ΄λ¦κ³Ό ν μ€νΈ λ΄μ©μ΄ 보μ΄κ³ , ν΅κ³Όλ κ²μ μ μ μμ΅λλ€.
μ΄λ²μλ ν μ€νΈ μ½λλ₯Ό assert.equal(response, "Hello World", "greeting message is wrong") λ‘ λ°κΏμ ν μ€νΈ μ€λ₯μ μ΄λ€ μΌμ΄ λ°μνλμ§ λ³΄λλ‘ νκ² μ΅λλ€.
μ΄λ κ² test κ° fail λμμμ 보μ¬μ£Όκ³ , assert.equal μμ μ€λ₯ λ©μμ§λ‘ μμ±ν λ΄μ© ("greeting message is wrong") μ΄ λ³΄μ΄λ©° μμν λ΄μ© (2λ²μ§Έ μΈμ, Hello World) μ μ€μ λ΄μ© (Hello World!) μ 보μ¬μ€λλ€.
+) μΆκ°λ‘ ν μ€νΈ μ½λ μμ± λ° μ€ν
μ΄λ²μλ HelloWorld 컨νΈλνΈμ μλ echo() ν¨μλ₯Ό ν μ€νΈν΄λ³΄λλ‘ νκ² μ΅λλ€.
ν μ€νΈ μ½λλ λ€μκ³Ό κ°μ΄ Promise λ₯Ό μ¬μ©ν κ²κ³Ό async/await λ₯Ό μ¬μ©ν κ²μ λ λ€ μμ±ν΄λ³΄μμ΅λλ€.
async/await λ‘ μμ±νλ©΄ μ½λμ κ°λ μ±μ΄ λμμ§λ κ²μ λ³Ό μ μμ΅λλ€.
var hello = artifacts.require("HelloWorld") contract("HelloWorld", function () { it ("is_echo_works_well_async", async function () { const instance = await hello.deployed(); const message = "testing"; const response = await instance.echo(message); assert.equal(response, message); }) it ("is_echo_works_well_promise", function () { return hello.deployed().then(function(instance) { const message = "testing"; instance.echo(message).then(function (response) { assert.equal(response, message); }) }) }) })
μ΄μ HelloWorldTest.js μλ μμ greet ν μ€νΈλ₯Ό ν©μ³ 3κ°μ§ ν μ€νΈ μΌμ΄μ€κ° μμ΅λλ€. (λ¬Όλ‘ 2κ°λ μμ± λ°©μλ§ λ€λ₯Έ κ²μ΄μ§λ§...)
μ΄λ₯Ό μ€νν΄λ³΄λ©΄ λ€μκ³Ό κ°μ κ²°κ³Όλ₯Ό μ»μ μ μμ΅λλ€.
μ΄κ²μΌλ‘ νΈλ¬νμμ μ리λν° ν μ€νΈ μ½λλ₯Ό μμ±νλ λ°©λ²μ μ΄ν΄λ³΄μμ΅λλ€.
'SECURITY > Blockchain' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ