测试与部署 #

一、测试策略 #

1.1 测试层次 #

测试类型 说明
单元测试 测试单个函数
集成测试 测试合约交互
端到端测试 测试完整流程
模糊测试 随机输入测试

1.2 测试原则 #

  • 测试所有公共函数
  • 测试边界条件
  • 测试错误情况
  • 测试权限控制

二、单元测试 #

2.1 Hardhat测试 #

javascript
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Token", function () {
  let token;
  let owner;
  let addr1;
  
  beforeEach(async function () {
    [owner, addr1] = await ethers.getSigners();
    
    const Token = await ethers.getContractFactory("Token");
    token = await Token.deploy("MyToken", "MTK", 1000000);
  });
  
  describe("Deployment", function () {
    it("Should set correct name", async function () {
      expect(await token.name()).to.equal("MyToken");
    });
    
    it("Should assign supply to owner", async function () {
      const balance = await token.balanceOf(owner.address);
      expect(balance).to.equal(ethers.utils.parseEther("1000000"));
    });
  });
  
  describe("Transfers", function () {
    it("Should transfer tokens", async function () {
      await token.transfer(addr1.address, 100);
      expect(await token.balanceOf(addr1.address)).to.equal(100);
    });
    
    it("Should fail if insufficient balance", async function () {
      await expect(
        token.connect(addr1).transfer(owner.address, 100)
      ).to.be.reverted;
    });
  });
});

2.2 Foundry测试 #

solidity
contract TokenTest is Test {
    Token public token;
    address public owner;
    address public user;
    
    function setUp() public {
        owner = address(this);
        user = address(0x1);
        token = new Token("MyToken", "MTK", 1000000);
    }
    
    function test_Name() public {
        assertEq(token.name(), "MyToken");
    }
    
    function test_Transfer() public {
        token.transfer(user, 100);
        assertEq(token.balanceOf(user), 100);
    }
    
    function testFail_InsufficientBalance() public {
        token.transfer(user, 1000000000);  // 应该失败
    }
    
    function testRevert_InsufficientBalance() public {
        vm.expectRevert("ERC20: transfer amount exceeds balance");
        token.transfer(user, 1000000000);
    }
}

三、模糊测试 #

3.1 Foundry模糊测试 #

solidity
contract FuzzTest is Test {
    Token public token;
    
    function setUp() public {
        token = new Token("Test", "TST", 1000000);
    }
    
    function testFuzz_Transfer(uint256 amount) public {
        vm.assume(amount <= token.balanceOf(address(this)));
        
        address user = address(0x1);
        uint256 balanceBefore = token.balanceOf(user);
        
        token.transfer(user, amount);
        
        assertEq(token.balanceOf(user), balanceBefore + amount);
    }
    
    function testFuzz_Approve(address spender, uint256 amount) public {
        token.approve(spender, amount);
        assertEq(token.allowance(address(this), spender), amount);
    }
}

四、部署流程 #

4.1 部署前检查 #

检查项 说明
合约审计 确保代码安全
测试覆盖 确保测试完整
Gas估算 估算部署成本
参数准备 准备构造函数参数

4.2 Hardhat部署 #

javascript
// scripts/deploy.js
const hre = require("hardhat");

async function main() {
  const [deployer] = await ethers.getSigners();
  
  console.log("Deploying contracts with account:", deployer.address);
  console.log("Account balance:", (await deployer.getBalance()).toString());
  
  const Token = await hre.ethers.getContractFactory("Token");
  const token = await Token.deploy("MyToken", "MTK", 1000000);
  await token.deployed();
  
  console.log("Token deployed to:", token.address);
  
  // 验证合约
  if (network.name !== "hardhat") {
    await hre.run("verify:verify", {
      address: token.address,
      constructorArguments: ["MyToken", "MTK", 1000000],
    });
  }
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

4.3 Foundry部署 #

solidity
// script/Deploy.s.sol
contract DeployScript is Script {
    function run() external {
        uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
        
        vm.startBroadcast(deployerPrivateKey);
        
        Token token = new Token("MyToken", "MTK", 1000000);
        
        vm.stopBroadcast();
    }
}
bash
forge script script/Deploy.s.sol --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY

五、CI/CD #

5.1 GitHub Actions #

yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Compile contracts
        run: npx hardhat compile
      
      - name: Run tests
        run: npx hardhat test
      
      - name: Run coverage
        run: npx hardhat coverage

六、总结 #

测试与部署要点:

类别 要点
测试 单元测试、集成测试、模糊测试
部署 检查、脚本、验证
CI/CD 自动化测试和部署

接下来,让我们学习DeFi应用!

最后更新:2026-03-27