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

STRK, ORDI, EGLD, OP và ARB là 5 token có mức lỗ cao nhất...

Đánh giá của Wu Blockchain cho biết, bất chấp sự gia tăng chung về vốn hóa thị trường tiền điện tử, nhiều mã vốn...

Yên Nhật giảm xuống mức thấp nhiều năm – 2025 là năm XRP lên...

Trong bối cảnh đồng Yên Nhật tiếp tục suy yếu, chạm mức thấp nhất trong nhiều năm khiến các nhà đầu tư lo lắng,...

Thanh khoản bên bán ETH suy giảm trên CEX: Đã đến lúc đạt 4.000...

Vào ngày 26/4, một nhà phân tích lưu ý có khả năng cao ETH sẽ tăng đột biến trong các phiên sắp tới do...

Giao dịch hàng ngày của BTC đạt kỷ lục mới – “Cơ hội thực...

Giao dịch Bitcoin đạt mức cao mọi thời đại mới với 926.842 giao dịch chỉ ba ngày sau sự kiện halving Bitcoin, vượt qua...

Các lãnh đạo sàn giao dịch crypto ACE Exchange Đài Loan bị đề nghị...

Các công tố viên Đài Loan đang đề xuất mức án tối thiểu 20 năm tù cho 4 nghi phạm chính trong vụ lừa...
Tin vắn Crypto

Tin vắn Crypto 27/04: Giá Bitcoin được dự đoán đạt 1 triệu đô la...

Từ dự đoán giá Bitcoin 1 triệu đô la trong bối cảnh in tiền cấp độ COVID đến Nga tiết lộ thí điểm hệ...

Giá MAVIA giảm hơn 15% sau khi game ‘Heroes of Mavia’ điều chỉnh lịch...

Chưa đầy ba tháng sau khi token MAVIA ra mắt, game chiến lược di động Heroes of Mavia đã điều chỉnh lại lịch trình...

Memecoin mèo Solana PAJAMAS tăng hơn 650% sau một tuần

Token chủ đề về mèo PAJAMAS đã tăng hơn 658% trong bảy ngày qua và đạt hiệu suất tốt nhất trong số các memecoin...

Bitcoin có thể phải đối mặt với áp lực bán hàng loạt trước thông...

Depository Trust and Clearing Corporation (DTCC) – một công ty dịch vụ tài chính cung cấp dịch vụ thanh toán bù trừ cho thị...

Cổ phiếu của Nvidia tăng 15% sau 5 ngày – Liệu các token AI...

Giá cổ phiếu của Nvidia (NVDA), nhà sản xuất đơn vị xử lý đồ họa (GPU) lớn nhất thế giới, đã phục hồi 15%...

Ngân hàng Republic First của Mỹ phá sản – cộng đồng tiền điện tử...

Các cơ quan quản lý Hoa Kỳ đã đóng cửa Ngân hàng Republic First có trụ sở tại Philadelphia, đánh dấu sự phá sản...
Renzo

Giải mã nguyên nhân người dùng ồ ạt thanh lý token restaking thanh khoản...

Giao thức staking thanh khoản Renzo tăng trưởng bùng nổ vào năm 2024, đạt mức cao nhất hơn 1 triệu ETH trong số tiền...
bitcoin

Năm biểu đồ cho thấy “sự thay đổi địa chấn” của tiền điện tử...

Bitcoin ETF đã làm được nhiều việc hơn ngoài khuyến khích các nhà đầu tư thu gom nhiều tiền điện tử hơn nữa. Theo...

Chìa khóa để hồi sinh Bitcoin Bull Run là Thông báo tái cấp vốn...

Vài tuần qua khá nhàm chán đối với các trader tiền điện tử vì Bitcoin (BTC), loại tiền điện tử hàng đầu theo giá...

Bộ sưu tập NFT đầu tiên của Grant Yun trên Solana cháy hàng trong...

Nghệ sĩ kỹ thuật số Grant Yun đã ra ra mắt bộ sưu tập NFT “Life in Japan” tái hiện lại những kỷ niệm...

Đây là chiến lược kiếm lợi nhuận cho nhà đầu tư Shiba Inu, theo...

Nhà phân tích tiền điện tử Crypto Noan đã tiết lộ một chiến lược chốt lời mà các nhà đầu tư tiền điện tử...