Testing applications on Paxeer Network follows the same principles as Ethereum development. This guide covers best practices specific to building reliable applications on Paxeer Network.
For most tests, you don’t need Paxeer-specific features. Use your development stack’s built-in testing tools for faster iteration.
// SPDX-License-Identifier: MITpragma solidity ^0.8.20;import "forge-std/Test.sol";import "../src/MyContract.sol";contract MyContractTest is Test { MyContract public myContract; address owner = address(1); address user = address(2); function setUp() public { vm.prank(owner); myContract = new MyContract(); } function testSetValue() public { myContract.setValue(42); assertEq(myContract.getValue(), 42); } function testEventEmission() public { vm.expectEmit(true, true, true, true); emit ValueChanged(42); myContract.setValue(42); } function testUnauthorized() public { vm.prank(user); vm.expectRevert("Not authorized"); myContract.adminFunction(); } function testFuzz_setValue(uint256 value) public { myContract.setValue(value); assertEq(myContract.getValue(), value); }}
# Create gas snapshotforge snapshot# Compare with previousforge snapshot --diff
Copy
contract GasTest is Test { function testGas_transfer() public { token.transfer(user, 100 ether); } function testGas_batchTransfer() public { address[] memory recipients = new address[](10); // ... test batch operation }}
describe("Edge Cases", function () { it("Should handle zero", async function () { await contract.setValue(0); }); it("Should handle max uint256", async function () { await contract.setValue(ethers.MaxUint256); }); it("Should handle empty arrays", async function () { await contract.processBatch([]); }); it("Should handle duplicate values", async function () { await contract.addItem(1); await expect(contract.addItem(1)).to.be.reverted; });});
Use Fuzzing
Foundry’s fuzzing finds edge cases automatically:
Copy
// Foundry will test with random valuesfunction testFuzz_transfer(uint256 amount) public { vm.assume(amount <= token.balanceOf(address(this))); token.transfer(user, amount); assertEq(token.balanceOf(user), amount);}function testFuzz_division(uint256 a, uint256 b) public { vm.assume(b != 0); uint256 result = a / b; assertLe(result, a);}
Test Events
Verify events are emitted correctly:
Copy
it("Should emit Transfer event", async function () { await expect(token.transfer(addr1.address, 100)) .to.emit(token, "Transfer") .withArgs(owner.address, addr1.address, 100);});
Time-based Testing
Test time-dependent functionality:
Copy
it("Should unlock after time period", async function () { await contract.lock(); // Fast forward time await ethers.provider.send("evm_increaseTime", [86400]); // 1 day await ethers.provider.send("evm_mine"); await contract.unlock();});
Foundry:
Copy
function testTimeLock() public { contract.lock(); // Warp time forward vm.warp(block.timestamp + 1 days); contract.unlock();}
describe("State Snapshots", function () { let snapshotId; beforeEach(async function () { snapshotId = await ethers.provider.send("evm_snapshot"); }); afterEach(async function () { await ethers.provider.send("evm_revert", [snapshotId]); }); it("Should test with clean state", async function () { // Each test starts with fresh state await contract.setValue(42); expect(await contract.getValue()).to.equal(42); });});
contract ReentrancyTest is Test { Vulnerable vulnerable; Attacker attacker; function setUp() public { vulnerable = new Vulnerable(); attacker = new Attacker(address(vulnerable)); } function testReentrancyAttack() public { vm.deal(address(vulnerable), 10 ether); vm.deal(address(attacker), 1 ether); vm.expectRevert("ReentrancyGuard: reentrant call"); attacker.attack(); }}
Access Control Testing
Copy
describe("Access Control", function () { it("Owner can perform admin actions", async function () { await expect(contract.connect(owner).adminAction()) .to.not.be.reverted; }); it("Non-owner cannot perform admin actions", async function () { await expect(contract.connect(user).adminAction()) .to.be.revertedWith("Ownable: caller is not the owner"); }); it("Should transfer ownership", async function () { await contract.transferOwnership(user.address); expect(await contract.owner()).to.equal(user.address); });});
Integer Overflow Testing
Copy
function testOverflow() public { uint256 max = type(uint256).max; // Should revert in 0.8+ vm.expectRevert(); uint256 overflow = max + 1;}