Last active
October 31, 2021 01:41
-
-
Save mingderwang/7ad5e844b254fcb9645dcdece2f19661 to your computer and use it in GitHub Desktop.
https://github.com/ethereum/remix-ide/blob/e32108c838c7a47fab60ac110a174f5b3d053706/docs/unittesting_examples.md (Testing by Example - Remix)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
contract AttendanceRegister { | |
struct Student{ | |
string name; | |
uint class; | |
} | |
event Added(string name, uint class, uint time); | |
mapping(uint => Student) public register; // roll number => student details | |
function add(uint rollNumber, string memory name, uint class) public returns (uint256){ | |
require(class > 0 && class <= 12, "Invalid class"); | |
require(register[rollNumber].class == 0, "Roll number not available"); | |
Student memory s = Student(name, class); | |
register[rollNumber] = s; | |
emit Added(name, class, now); | |
return rollNumber; | |
} | |
function getStudentName(uint rollNumber) public view returns (string memory) { | |
return register[rollNumber].name; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
import "remix_tests.sol"; // this import is automatically injected by Remix. | |
import "./AttendanceRegister.sol"; | |
contract AttendanceRegisterTest { | |
AttendanceRegister ar; | |
/// 'beforeAll' runs before all other tests | |
function beforeAll () public { | |
// Create an instance of contract to be tested | |
ar = new AttendanceRegister(); | |
} | |
/// For solidity version greater or equal to 0.6.0, | |
/// See: https://solidity.readthedocs.io/en/v0.6.0/control-structures.html#try-catch | |
/// Test 'add' using try-catch | |
function testAddSuccessUsingTryCatch() public { | |
// This will pass | |
try ar.add(101, 'secondStudent', 11) returns (uint256 r) { | |
Assert.equal(r, 101, 'wrong rollNumber'); | |
} catch Error(string memory /*reason*/) { | |
// This is executed in case | |
// revert was called inside getData | |
// and a reason string was provided. | |
Assert.ok(false, 'failed with reason'); | |
} catch (bytes memory /*lowLevelData*/) { | |
// This is executed in case revert() was used | |
// or there was a failing assertion, division | |
// by zero, etc. inside getData. | |
Assert.ok(false, 'failed unexpected'); | |
} | |
} | |
/// Test failure case of 'add' using try-catch | |
function testAddFailureUsingTryCatch1() public { | |
// This will revert on 'require(class > 0 && class <= 12, "Invalid class");' for class '13' | |
try ar.add(101, 'secondStudent', 13) returns (uint256 r) { | |
Assert.ok(false, 'method execution should fail'); | |
} catch Error(string memory reason) { | |
// Compare failure reason, check if it is as expected | |
Assert.equal(reason, 'Invalid class', 'failed with unexpected reason'); | |
} catch (bytes memory /*lowLevelData*/) { | |
Assert.ok(false, 'failed unexpected'); | |
} | |
} | |
/// Test another failure case of 'add' using try-catch | |
function testAddFailureUsingTryCatch2() public { | |
// This will revert on 'require(register[rollNumber].class == 0, "Roll number not available");' for rollNumber '101' | |
try ar.add(101, 'secondStudent', 11) returns (uint256 r) { | |
Assert.ok(false, 'method execution should fail'); | |
} catch Error(string memory reason) { | |
// Compare failure reason, check if it is as expected | |
Assert.equal(reason, 'Roll number not available', 'failed with unexpected reason'); | |
} catch (bytes memory /*lowLevelData*/) { | |
Assert.ok(false, 'failed unexpected'); | |
} | |
} | |
/// For solidity version less than 0.6.0, low level call can be used | |
/// See: https://solidity.readthedocs.io/en/v0.6.0/units-and-global-variables.html#members-of-address-types | |
/// Test success case of 'add' using low level call | |
function testAddSuccessUsingCall() public { | |
bytes memory methodSign = abi.encodeWithSignature('add(uint256,string,uint256)', 102, 'firstStudent', 10); | |
(bool success, bytes memory data) = address(ar).call(methodSign); | |
// 'success' stores the result in bool, this can be used to check whether method call was successful | |
Assert.equal(success, true, 'execution should be successful'); | |
// 'data' stores the returned data which can be decoded to get the actual result | |
uint rollNumber = abi.decode(data, (uint256)); | |
// check if result is as expected | |
Assert.equal(rollNumber, 102, 'wrong rollNumber'); | |
} | |
/// Test failure case of 'add' using low level call | |
function testAddFailureUsingCall() public { | |
bytes memory methodSign = abi.encodeWithSignature('add(uint256,string,uint256)', 102, 'duplicate', 10); | |
(bool success, bytes memory data) = address(ar).call(methodSign); | |
// 'success' will be false if method execution is not successful | |
Assert.equal(success, false, 'execution should be successful'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity ^0.8.4; | |
contract donations{ | |
struct Donation { | |
uint id; | |
uint amount; | |
string donor; | |
string message; | |
uint timestamp; //seconds since unix start | |
} | |
uint amount = 0; | |
uint id = 0; | |
mapping(address => uint) public balances; | |
mapping(address => Donation[]) public donationsMap; | |
function donate(address _recipient, string memory _donor, string memory _msg) public payable { | |
require(msg.value > 0, "The donation needs to be >0 in order for it to go through"); | |
amount = msg.value; | |
balances[_recipient] += amount; | |
donationsMap[_recipient].push(Donation(id++,amount,_donor,_msg,block.timestamp)); | |
} | |
function withdraw() public { //whole thing by default. | |
amount = balances[msg.sender]; | |
balances[msg.sender] -= amount; | |
require(amount > 0, "Your current balance is 0"); | |
(bool success,) = msg.sender.call{value:amount}(""); | |
if(!success){ | |
revert(); | |
} | |
} | |
function balances_getter(address _recipient) public view returns (uint){ | |
return balances[_recipient]; | |
} | |
function getBalance() public view returns(uint) { | |
return msg.sender.balance; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.4.22 <0.9.0; | |
import "remix_tests.sol"; | |
import "remix_accounts.sol"; | |
import "../donations.sol"; | |
contract testSuite is donations { | |
address acc0 = TestsAccounts.getAccount(0); //owner by default | |
address acc1 = TestsAccounts.getAccount(1); | |
address acc2 = TestsAccounts.getAccount(2); | |
address acc3 = TestsAccounts.getAccount(3); | |
address recipient = TestsAccounts.getAccount(4); //recipient | |
/// #value: 1000000000000000000 | |
/// #sender: account-1 | |
function donateAcc1AndCheckBalance() public payable{ | |
Assert.equal(msg.value, 1000000000000000000, 'value should be 1 Eth'); | |
donate(recipient, "Mario", "Are you a bird?"); | |
Assert.equal(balances_getter(recipient), 1000000000000000000, 'balances should be 1 Eth'); | |
} | |
/// #value: 1000000000000000000 | |
/// #sender: account-2 | |
function donateAcc2AndCheckBalance() public payable{ | |
Assert.equal(msg.value, 1000000000000000000, 'value should be 1 Eth'); | |
donate(recipient, "Tom", "Are you a plane?"); | |
Assert.equal(balances_getter(recipient), 2000000000000000000, 'balances should be 2 Eth'); | |
} | |
/// #value: 2000000000000000000 | |
/// #sender: account-3 | |
function donateAcc3AndCheckBalance() public payable{ | |
Assert.equal(msg.value, 2000000000000000000, 'value should be 1 Eth'); | |
donate(recipient, "Maria", "Are you a car?"); | |
Assert.equal(balances_getter(recipient), 4000000000000000000, 'balances should be 4 Eth'); | |
} | |
/// #sender: account-4 | |
function withdrawDonations() public payable{ | |
uint initialBal = getBalance(); | |
withdraw(); | |
uint finalBal = getBalance(); | |
Assert.equal(finalBal-initialBal, 4000000000000000000, 'balances should be 4 Eth'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
contract Sender { | |
address private owner; | |
constructor() public { | |
owner = msg.sender; | |
} | |
function updateOwner(address newOwner) public { | |
require(msg.sender == owner, "only current owner can update owner"); | |
owner = newOwner; | |
} | |
function getOwner() public view returns (address) { | |
return owner; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
import "remix_tests.sol"; // this import is automatically injected by Remix | |
import "remix_accounts.sol"; | |
import "./Sender.sol"; | |
// Inherit 'Sender' contract | |
contract SenderTest is Sender { | |
/// Define variables referring to different accounts | |
address acc0; | |
address acc1; | |
address acc2; | |
/// Initiate accounts variable | |
function beforeAll() public { | |
acc0 = TestsAccounts.getAccount(0); | |
acc1 = TestsAccounts.getAccount(1); | |
acc2 = TestsAccounts.getAccount(2); | |
} | |
/// Test if initial owner is set correctly | |
function testInitialOwner() public { | |
// account at zero index (account-0) is default account, so current owner should be acc0 | |
Assert.equal(getOwner(), acc0, 'owner should be acc0'); | |
} | |
/// Update owner first time | |
/// This method will be called by default account(account-0) as there is no custom sender defined | |
function updateOwnerOnce() public { | |
// check method caller is as expected | |
Assert.ok(msg.sender == acc0, 'caller should be default account i.e. acc0'); | |
// update owner address to acc1 | |
updateOwner(acc1); | |
// check if owner is set to expected account | |
Assert.equal(getOwner(), acc1, 'owner should be updated to acc1'); | |
} | |
/// Update owner again by defining custom sender | |
/// #sender: account-1 (sender is account at index '1') | |
function updateOwnerOnceAgain() public { | |
// check if caller is custom and is as expected | |
Assert.ok(msg.sender == acc1, 'caller should be custom account i.e. acc1'); | |
// update owner address to acc2. This will be successful because acc1 is current owner & caller both | |
updateOwner(acc2); | |
// check if owner is set to expected account i.e. account2 | |
Assert.equal(getOwner(), acc2, 'owner should be updated to acc2'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
contract SimpleStorage { | |
uint public storedData; | |
constructor() public { | |
storedData = 100; | |
} | |
function set(uint x) public { | |
storedData = x; | |
} | |
function get() public view returns (uint retVal) { | |
return storedData; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
import "remix_tests.sol"; | |
import "./Simple_storage.sol"; | |
contract MyTest { | |
SimpleStorage foo; | |
// beforeEach works before running each test | |
function beforeEach() public { | |
foo = new SimpleStorage(); | |
} | |
/// Test if initial value is set correctly | |
function initialValueShouldBe100() public returns (bool) { | |
return Assert.equal(foo.get(), 100, "initial value is not correct"); | |
} | |
/// Test if value is set as expected | |
function valueIsSet200() public returns (bool) { | |
foo.set(200); | |
return Assert.equal(foo.get(), 200, "value is not 200"); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
contract Value { | |
uint256 public tokenBalance; | |
constructor() public { | |
tokenBalance = 0; | |
} | |
function addValue() payable public { | |
tokenBalance = tokenBalance + (msg.value/10); | |
} | |
function getTokenBalance() view public returns (uint256) { | |
return tokenBalance; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity >=0.4.22 <0.7.0; | |
import "remix_tests.sol"; | |
import "./Value.sol"; | |
contract ValueTest{ | |
Value v; | |
function beforeAll() public { | |
// create a new instance of Value contract | |
v = new Value(); | |
} | |
/// Test initial balance | |
function testInitialBalance() public { | |
// initially token balance should be 0 | |
Assert.equal(v.getTokenBalance(), 0, 'token balance should be 0 initially'); | |
} | |
/// For Solidity version greater than 0.6.1 | |
/// Test 'addValue' execution by passing custom ether amount | |
/// #value: 200 | |
function addValueOnce() public payable { | |
// check if value is same as provided through devdoc | |
Assert.equal(msg.value, 200, 'value should be 200'); | |
// execute 'addValue' | |
v.addValue{gas: 40000, value: 200}(); // introduced in Solidity version 0.6.2 | |
// As per the calculation, check the total balance | |
Assert.equal(v.getTokenBalance(), 20, 'token balance should be 20'); | |
} | |
/// For Solidity version less than 0.6.2 | |
/// Test 'addValue' execution by passing custom ether amount again using low level call | |
/// #value: 100 | |
function addValueAgain() public payable { | |
Assert.equal(msg.value, 100, 'value should be 100'); | |
bytes memory methodSign = abi.encodeWithSignature('addValue()'); | |
(bool success, bytes memory data) = address(v).call.gas(40000).value(100)(methodSign); | |
Assert.equal(success, true, 'execution should be successful'); | |
Assert.equal(v.getTokenBalance(), 30, 'token balance should be 30'); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment