Trang chủ Tạp chí Lập trình smart contract: Phần 5 — Viết test case cho smart contracts

Lập trình smart contract: Phần 5 — Viết test case cho smart contracts

Tiếp tục loạt bài thực tế phát triển dApp, giờ chúng ta sẽ nâng độ khó lên một chút xíu khi đi vào hoàn thiện nội dung của smart contracts và viết test case kiểm thử.

Smart contracts

Events

Các smart contracts được thực thi trong môi trường của EVM, hoàn toàn tách biệt với môi trường bên ngoài. Để có thể trigger một sự kiệu ra bên ngoài EVM ta gửi các events được định nghĩa trước:

//New job append
 event NewJob(
 uint256 indexed id,
 address creator,
 uint256 salary,
 uint256 timeOut);

//An woker start working
 event TakeJob(
 uint256 indexed id,
 address indexed labor);

Các event này có thể lắng nghe thông qua các filter cung cấp bởi web3js, việc này sẽ cung cấp thêm thông tin, trigger các hệ thống third party hoặc đơn giản là điều chỉnh lại front-end.

Modifier

Để smart contract của mình bảo mật hơn, mình thêm các modifier. Mục tiêu là kiểm tra arguments trước khi method được trigger (Ethereum là một hệ hoàn toàn thụ động, không có khả năng tự tính toán).

//Transaction must contant Ethereum
 modifier onlyHaveFund {
 require(msg.value > MINIUM_SALARY);
 _;
 }

Trên đây bạn có thể đọc thấy modifier rất rõ nghĩa, với modifier này mình check số Ethereum có trong transaction. Biến msg sẽ chứa vài thông tin hữu ích của transaction (eg. msg.sender: address của người gửi, msg.value: số ethereum tính bằng wei). Để biết rõ thêm global variable các bạn xem ở đây.

Smart contract

Mình viết lại smart contract, thêm hai function mới takeJob() và viewJob():

//Take job

function

takeJob (uint256 jobId)

public onlyValidMortgage(jobId) onlyValidId(jobId) onlyValidJob(jobId)

{

//Trigger event to log labor

TakeJob(jobId, msg.sender);



//Change working state

jobData[jobId].start = block.timestamp;

}



//Veiw job data

function

viewJob(uint256 jobId)

public onlyValidId(jobId) constant returns (

uint256 id,

address creator,

uint256 salary,

uint256 start,

uint256 end,

uint256 timeOut,

bytes title,

bytes description)

{

Job memory jobReader = jobData[jobId];

return (jobReader.id,

jobReader.creator,

jobReader.salary,

jobReader.start,

jobReader.end,

jobReader.timeOut,

jobReader.title,

jobReader.description);

}

Trong phần struct mình cũng update thêm các biến liên quan tới thời gian, và để tiện xử lý mình sẽ sữ dụng Unix timestamp (Solidity không có kiểu datime nên dùng Unix time là tiện nhất):

uint256 start;

uint256 end;

uint256 timeOut;

Chúng ta có toàn bộ mã nguồn như sau:

pragma solidity ^0.4.18;





contract PartTime {



//Job structure

struct Job {

uint256 id;

address creator;

uint256 salary;

uint256 start;

uint256 end;

uint256 timeOut;

bytes title;

bytes description;

}



//New job append

event NewJob(uint256 indexed id,

address creator,

uint256 salary,

uint256 timeOut);



//An woker start working

event TakeJob(

uint256 indexed id,

address indexed labor);



//Minium accept salary

uint256 constant public MINIUM_SALARY = 0.1 ether;



//The number of jobs

uint256 public totalJob;



//Mapped data

mapping (uint256 => Job) public jobData;



//Transaction must contant Ethereum

modifier onlyHaveFund {

require(msg.value > MINIUM_SALARY);

_;

}



//Valid timeOut should be greater than 3 days

modifier onlyValidTimeOut(uint256 timeOut) {

require(timeOut > 3 days);

_;

}



//Check valid job Id

modifier onlyValidId(uint256 jobId) {

require(jobId < totalJob);

_;

}



//Mortgage should be greater than 1/10

modifier onlyValidMortgage(uint256 jobId) {

require(msg.value > jobData[jobId].salary/10);

_;

}



//Check is it a taked job

modifier onlyValidJob(uint256 jobId) {

require(jobData[jobId].end == 0);

require(jobData[jobId].start == 0);

_;

}



//Append new job to mapping

function

createJob (uint256 timeOut, bytes title, bytes description)

public onlyHaveFund onlyValidTimeOut(timeOut) payable returns(uint256 jobId)

{

// Saving a little gas by create a temporary object

Job memory newJob;



// Assign jobId

jobId = totalJob;



newJob.id = jobId;

newJob.id = timeOut;

newJob.title = title;

newJob.description = description;

newJob.salary = msg.value;

newJob.creator = msg.sender;



//Trigger event

NewJob(jobId, msg.sender, msg.value, timeOut);



// Append newJob to jobData

jobData[totalJob++] = newJob;



return jobId;

}



//Take job

function

takeJob (uint256 jobId)

public onlyValidMortgage(jobId) onlyValidId(jobId) onlyValidJob(jobId)

{

//Trigger event to log labor

TakeJob(jobId, msg.sender);



//Change working state

jobData[jobId].start = block.timestamp;

}



//Veiw job data

function

viewJob(uint256 jobId)

public onlyValidId(jobId) constant returns (

uint256 id,

address creator,

uint256 salary,

uint256 start,

uint256 end,

uint256 timeOut,

bytes title,

bytes description)

{

Job memory jobReader = jobData[jobId];

return (jobReader.id,

jobReader.creator,

jobReader.salary,

jobReader.start,

jobReader.end,

jobReader.timeOut,

jobReader.title,

jobReader.description);

}



}

Và mình viết thêm test case bằng JavaScript:

var Partime = artifacts.require("./PartTime.sol");



function createTx(from, to, value = 0, gas = 1000000, gasPrice = 20000000) {

return {

from: from,

to: to,

gas: gas,

gasPrice: gasPrice,

value: value

};

}



contract('Partime', function (accounts) {



it('should have 0 total part time job', function () {

return Partime.deployed().then(function (instance) {

return instance.totalJob.call();

}).then(function (totalJob) {

assert.equal(totalJob.valueOf(), 0, 'Total job was not equal to 0');

});

});



it('should able to add new job', function () {

return Partime.deployed().then(function (instance) {

return instance.createJob(((new Date()).getTime() / 1000 + 432000),

"This is tittle",

"This is description",

createTx(accounts[0], instance.address, web3.toWei('1', 'ether')));

}).then(function (totalJob) {

assert.equal(typeof (totalJob.valueOf()), 'object', 'Transaction was not triggered success');

});

});



it('should have total part time job geater than 0', function () {

return Partime.deployed().then(function (instance) {

return instance.totalJob.call();

}).then(function (totalJob) {

assert.equal(totalJob.valueOf() > 0, true, 'Total job was equal to 0' );

});

});



});

Bạn chú ý thấy mình đang thêm 1 job mới:

return instance.createJob(((new Date()).getTime() / 1000 + 432000),

"This is tittle",

"This is description",

createTx(accounts[0], instance.address, web3.toWei('1', 'ether')));

Đoạn code này có nghĩa là mình tạo ra 1 job có

  • Timeout: 5 ngày
  • Title: This is tittle
  • Description: This is description
  • Value: 1 Ethereum

Thực thi kiểm thử:

Smart contracts

Mình đã update source code tại https://github.com/chiro-hiro/part-time-dapp. Các bạn có thể clone về hoặc fork về viết cùng mình cho vui.

Dislaimer: Đây là thông tin cung cấp dưới dạng blog cá nhân, không phải thông tin tổng hợp hay lời khuyên đầu tư. Chúng tôi không chịu trách nhiệm về các quyết định đầu tư của bạn.

MỚI CẬP NHẬT

Solana

Solana chuẩn bị phục hồi hay tiếp tục suy thoái trong quý 2?

Solana (SOL) đã khởi đầu năm 2025 với quý 1 đầy khó khăn, giảm 34% và mất 100 tỷ đô la vốn hóa thị...
Bitcoin

Funding rate chuyển sang âm có ý nghĩa gì đối với tương lai của...

Trong 30 ngày qua, giá Bitcoin giảm khoảng 8,3%, xuống thấp hơn gần 30% so với mức cao nhất mọi thời đại. Tuy nhiên,...

Các cơ quan thương mại Anh kêu gọi chính phủ xem tiền điện tử...

Các hiệp hội thương mại hàng đầu tại Anh đã gửi lời kêu gọi tới văn phòng Thủ tướng Keir Starmer, đề xuất bổ...
Hacker Triều Tiên nhắm vào các công ty blockchain của Anh

Hacker Triều Tiên nhắm vào các công ty blockchain của Anh trong bối cảnh...

Các nhân viên công nghệ lừa đảo có liên hệ với Triều Tiên đang mở rộng hoạt động xâm nhập vào các công ty...
usdt Bitcoin

Hơn $1 tỷ USDT được đúc khi các nhà đầu tư Bitcoin chuẩn bị...

Bitcoin, tiền điện tử lớn nhất thế giới theo vốn hóa thị trường, đang có xu hướng tăng giá và chuẩn bị cho một...

Coinbase nhận 50% doanh thu dư từ dự trữ USDC của Circle

Sàn giao dịch Coinbase Global nhận được một nửa doanh thu dư từ Circle, phát sinh từ các quỹ dự trữ hỗ trợ stablecoin...
bitcoin

Holder Bitcoin ngắn hạn không bán tháo bất kể thua lỗ

Theo một bài đăng gần đây từ CryptoQuant Quicktake, các holder Bitcoin ngắn hạn chọn giữ tài sản kỹ thuật số của mình mặc...

Thượng nghị sỹ Mỹ tái giới thiệu dự luật hưu trí tiền điện tử...

Lần thứ ba, Thượng nghị sĩ Alabama, Tommy Tuberville, chuẩn bị tái giới thiệu một dự luật nhằm cho phép người dân Mỹ bổ...

Lạc quan ngắn hạn khi khối lượng hợp đồng BTC tăng vọt trên Binance...

Trên sàn Binance và OKX, ba cặp hợp đồng tương lai vĩnh cửu phổ biến nhất đã ghi nhận mức tăng giá đáng kể...

American Bitcoin liên kết với Trump có kế hoạch IPO

American Bitcoin Corp., một công ty khai thác tiền điện tử được hậu thuẫn bởi gia đình Trump, đang có kế hoạch huy động...

Uniswap DAO ủng hộ chương trình ‘Treasury Delegation’ trị giá 113 triệu USD để...

Theo cuộc bỏ phiếu quản trị sơ bộ kết thúc vào hôm thứ Ba, Uniswap DAO đã bỏ phiếu để tiếp tục "chương trình...
eth-phuc-hoi

Ethereum (ETH) nỗ lực phục hồi khi đà giảm đang dần suy yếu

Ethereum (ETH) bước vào tuần mới với những tín hiệu trái ngược khi các trader đón nhận thông báo thuế "Ngày Giải Phóng" vào...
Metaplanet tiếp tục đẩy mạnh chiến lược tích lũy Bitcoin

Metaplanet tiếp tục đẩy mạnh chiến lược tích lũy Bitcoin, nâng tổng số nắm...

Metaplanet, công ty niêm yết tại Tokyo, vừa công bố vào thứ Tư rằng họ đã bổ sung thêm 160 Bitcoin vào kho dự...
NEO

Neo Foundation phủ nhận việc bán token, điều tra chuyển khoản Binance sau khi...

Neo Foundation khẳng đinh không dính líu đến các giao dịch bán token NEO gần đây, sau khi giá trị giảm 35,85% từ ngày...

Nhiều altcoin sụp đổ vào ngày Cá tháng Tư, thị trường crypto vẫn ổn...

Một số altcoin và memecoin đã chứng kiến ​​đợt bán tháo mạnh vào Ngày Cá tháng Tư, với một số token, bao gồm Act...
sui-kho-khan

SUI gặp khó khăn dưới mức kháng cự khi mở khóa token trị giá...

Hôm nay, SUI đứng trước một thử thách quan trọng khi đợt mở khóa token trị giá 147 triệu USD có thể tạo ra...