单元测试:truffle的单元测试可以用js或者solidity。他们的区别在于:
1、solidity在测试合约的时候,由于msg.sender是测试合约,所以不能使用账号进行转账的测试,大多数情况,用来测试输入是否合理;
2、js在测试合约的时候,可以设置合约的发送者,测试比solidity要方便,可以测试复杂的业务逻辑。
注意,单元测试要测试尽可能多的情况,把你能想到的所有可能输入的值以及所有可能会存在的异常情况都进行测试。
以下是我编写的单元测试,我主要是举例为主,因此单元测试的情况没有那么全:
solidity单元测试:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "truffle/build/Assert.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "../contracts/Pool.sol";
//质押代币合约、质押奖励合约、每分钟奖励数量
address constant stakeTokenAddr = 0x3A96edFe9C0D71748061bE544e7Db07828644FA8;
address constant rewardTokenAddr = 0x3A96edFe9C0D71748061bE544e7Db07828644FA8;
uint256 constant rewardPerMin = 100;
contract TestPool {
//创建质押合约
Pool tpool;
//质押token地址
IERC20 stakeToken;
//质押奖励token地址
IERC20 rewardToken;
constructor(){
stakeToken = IERC20(stakeTokenAddr);
rewardToken = IERC20(rewardTokenAddr);
}
function beforeEach() public {
tpool = new Pool(stakeTokenAddr, rewardTokenAddr, rewardPerMin);
}
function testStake002Throw() public {
bool r;
(r, ) = address(this).call(abi.encodePacked(this.stake001.selector));
Assert.isFalse(r, "If this is true, stake() transfer amount exceeds balance!");
}
function testStake003Throw() public {
bool r;
(r, ) = address(this).call(abi.encodePacked(this.stake002.selector));
Assert.isFalse(r, "If this is true, stake() can input 0!");
}
//质押数量超过拥有的数量
function stake001() public {
//质押前,msg.sender的质押代币的数量
uint256 amount_before = stakeToken.balanceOf(msg.sender);
tpool.stake(amount_before + 1);
}
//质押数量为0
function stake002() public {
tpool.stake(0);
}
//解押数量为0
function testunStake001() public {
tpool.unStake(0);
}
//解押数量大于已质押数量
function testunStake002() public {
tpool.unStake(1);
}
//提现数量为0
function testwithdraw001() public {
tpool.withdraw(0);
}
//提现数量大于可提现数量
function testwithdraw002() public {
tpool.withdraw(1);
}
//可提现数量为0
function testWithdrawRewardAmountShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.canWithdrawReward(), expected, "WITHDRAW_REWARD_AMOUNT_SHOULD_BE_ZERO");
}
//已提现数量为0
function testWithdrawdRewardAmountShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.hadWithdrawReward(), expected, "WITHDRAWD_REWARD_AMOUNT_SHOULD_BE_ZERO");
}
//累计奖励为0
function testAddupRewardAmountShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.addupReward(), expected, "ADDUP_REWARD_AMOUNT_SHOULD_BE_ZERO");
}
//质押份额为0
function testShareShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.getShare(), expected, "SHARE_SHOULD_BE_ZERO");
}
//总质押份额为0
function testTotalSharesShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.totalShares(), expected, "TOTAL_SHARES_SHOULD_BE_ZERO");
}
//总挖矿奖励为0
function testTotalRewardShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.totalReward(), expected, "TOTAL_REWARD_SHOULD_BE_ZERO");
}
//每份额累计总奖励为0
function testAddUpRewardPerShareShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.addUpRewardPerShare(), expected, "ADDUP_REWARD_PER_SHARES_SHOULD_BE_ZERO");
}
//每份额累计总奖励为0
function testlastAddUpRewardPerShareAllShouldBeZero() public {
uint256 expected = 0;
Assert.equal(tpool.lastAddUpRewardPerShareAll(), expected, "LAST_ADDUP_REWARD_PER_SHARES_SHOULD_BE_ZERO");
}
}
js测试源码:
const Pool = artifacts.require('Pool');
const IErc20 = artifacts.require('interface/IErc20');
const erc20_address = "0x3A96edFe9C0D71748061bE544e7Db07828644FA8";
contract("Pool", accounts => {
//质押100个,预期10个
it("test stake 100 token in first account", async ()=>{
let pool = await Pool.deployed();
let erc20 = await IErc20.at(erc20_address);
let amount = 100;
let staker = accounts[0];
let start_token_amount = await erc20.balanceOf(staker);
let start_token_amount_num = BigInt(start_token_amount.toString());
await erc20.approve(pool.address, amount);
await pool.stake(amount);
let end_token_amount = await erc20.balanceOf.call(staker);
let end_token_amount_num = BigInt(end_token_amount.toString());
assert.equal(
start_token_amount_num - end_token_amount_num,
amount,
"stake token amount is error"
);
let total_shares = await pool.totalShares();
let total_shares_num = BigInt(total_shares.toString());
let my_shares = await pool.getShare();
let my_shares_num = BigInt(my_shares.toString());
//总份额
assert.equal(
total_shares_num,
amount,
"total shares is error"
);
//质押份额
assert.equal(
my_shares_num,
amount,
"total shares is error"
);
});
//解押10个,预期10个
it("test unstake 10 token from first account", async ()=>{
let pool = await Pool.deployed();
let erc20 = await IErc20.at(erc20_address);
let amount = 10;
let unstaker = accounts[0];
let start_token_amount = await erc20.balanceOf(unstaker);
let start_token_amount_num = BigInt(start_token_amount.toString());
//await erc20.approve(pool.address, amount);
await pool.unStake(amount);
let end_token_amount = await erc20.balanceOf.call(unstaker);
let end_token_amount_num = BigInt(end_token_amount.toString());
assert.equal(
end_token_amount_num - start_token_amount_num,
amount,
"stake token amount is error"
);
let total_shares = await pool.totalShares();
let total_shares_num = BigInt(total_shares.toString());
let my_shares = await pool.getShare();
let my_shares_num = BigInt(my_shares.toString());
//总份额
assert.equal(
total_shares_num,
100-amount,
"total shares is error"
);
//质押份额
assert.equal(
my_shares_num,
100-amount,
"total shares is error"
);
});
//解押100个,预期报错
it("test unstake 100 token from first account", async ()=>{
let pool = await Pool.deployed();
let erc20 = await IErc20.at(erc20_address);
let amount = 100;
let unstaker = accounts[0];
let start_token_amount = await erc20.balanceOf(unstaker);
let start_token_amount_num = BigInt(start_token_amount.toString());
//await erc20.approve(pool.address, amount);
await pool.unStake(amount);
let end_token_amount = await erc20.balanceOf.call(unstaker);
let end_token_amount_num = BigInt(end_token_amount.toString());
assert.equal(
end_token_amount_num - start_token_amount_num,
amount,
"stake token amount is error"
);
});
//解押90个,预期90个
it("test unstake 90 token from first account", async ()=>{
let pool = await Pool.deployed();
let erc20 = await IErc20.at(erc20_address);
let amount = 90;
let unstaker = accounts[0];
let start_token_amount = await erc20.balanceOf(unstaker);
let start_token_amount_num = BigInt(start_token_amount.toString());
//await erc20.approve(pool.address, amount);
await pool.unStake(amount);
let end_token_amount = await erc20.balanceOf.call(unstaker);
let end_token_amount_num = BigInt(end_token_amount.toString());
assert.equal(
end_token_amount_num - start_token_amount_num,
amount,
"stake token amount is error"
);
let total_shares = await pool.totalShares();
let total_shares_num = BigInt(total_shares.toString());
let my_shares = await pool.getShare();
let my_shares_num = BigInt(my_shares.toString());
//总份额
assert.equal(
total_shares_num,
0,
"total shares is error"
);
//质押份额
assert.equal(
my_shares_num,
0,
"total shares is error"
);
});
})