Testing
Complete testing framework and best practices for MemeTrade smart contracts, APIs, and integrations. Learn how to test locally, on testnets, and in production environments.
Testing Environment Setup
Local Development Environment
Prerequisites:
# Install Foundry (recommended)
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Or install Hardhat
npm install -g hardhat
# Install Node.js dependencies
npm install ethers dotenv @nomiclabs/hardhat-ethers
Environment Configuration:
# .env file
BASE_SEPOLIA_RPC_URL="https://sepolia.base.org"
BASE_MAINNET_RPC_URL="https://mainnet.base.org"
PRIVATE_KEY="your-test-private-key"
MEMETRADE_API_KEY="your-api-key"
ETHERSCAN_API_KEY="your-etherscan-key"
Foundry Testing Setup
foundry.toml Configuration:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.19"
optimizer = true
optimizer_runs = 200
via_ir = true
[profile.default.fuzz]
runs = 1000
[profile.default.invariant]
runs = 256
depth = 15
fail_on_revert = false
[rpc_endpoints]
base_sepolia = "${BASE_SEPOLIA_RPC_URL}"
base_mainnet = "${BASE_MAINNET_RPC_URL}"
[etherscan]
base_sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api-sepolia.basescan.org/api" }
base = { key = "${ETHERSCAN_API_KEY}", url = "https://api.basescan.org/api" }
Smart Contract Testing
Unit Testing with Foundry
Basic Test Structure:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/Factory.sol";
import "../src/templates/Template.sol";
contract FactoryTest is Test {
Factory public factory;
address public owner = address(0x1);
address public user = address(0x2);
event TokenCreated(
address indexed token,
address indexed creator,
string name,
string symbol
);
function setUp() public {
vm.startPrank(owner);
factory = new Factory();
vm.stopPrank();
}
function testCreateToken() public {
vm.startPrank(user);
vm.deal(user, 1 ether);
// Expect TokenCreated event
vm.expectEmit(true, true, false, true);
emit TokenCreated(
address(0), // We don't know the address yet
user,
"Test Token",
"TEST"
);
address tokenAddress = factory.createToken{value: 0.001 ether}(
"Test Token",
"TEST",
"A test token",
"https://example.com/image.png",
250, // 2.5% creator fee
0 // Basic template
);
// Verify token was created
assertNotEq(tokenAddress, address(0));
// Verify token properties
Template token = Template(tokenAddress);
assertEq(token.name(), "Test Token");
assertEq(token.symbol(), "TEST");
assertEq(token.creator(), user);
vm.stopPrank();
}
function testCreateTokenInsufficientFee() public {
vm.startPrank(user);
vm.deal(user, 0.0005 ether); // Insufficient fee
vm.expectRevert("Insufficient creation fee");
factory.createToken{value: 0.0005 ether}(
"Test Token",
"TEST",
"A test token",
"https://example.com/image.png",
250,
0
);
vm.stopPrank();
}
}
Advanced Testing Patterns:
contract TemplateTest is Test {
Template public token;
address public creator = address(0x1);
address public trader = address(0x2);
function setUp() public {
vm.startPrank(creator);
token = new Template();
token.initialize(
"Test Token",
"TEST",
"Description",
"https://image.url",
creator,
250 // 2.5% fee
);
vm.stopPrank();
}
function testFuzzTokenCreation(
string memory name,
string memory symbol,
uint256 creatorFee
) public {
// Bound inputs to valid ranges
vm.assume(bytes(name).length > 0 && bytes(name).length <= 50);
vm.assume(bytes(symbol).length > 0 && bytes(symbol).length <= 10);
creatorFee = bound(creatorFee, 0, 500); // 0-5%
Template testToken = new Template();
testToken.initialize(
name,
symbol,
"Test description",
"https://test.com/image.png",
creator,
creatorFee
);
assertEq(testToken.name(), name);
assertEq(testToken.symbol(), symbol);
assertEq(testToken.creatorFee(), creatorFee);
}
function testInvariantTokenSupply() public {
// Token supply should never exceed max supply
uint256 maxSupply = token.MAX_SUPPLY();
assertTrue(token.totalSupply() <= maxSupply);
// Creator should always own initial supply
assertTrue(token.balanceOf(creator) > 0);
}
}
Fuzz Testing
Property-Based Testing:
contract LiquidityInvariantTest is Test {
using stdInvariant for StdInvariantFuzzInterface;
LiquidityMiningHelper public liquidityMining;
ERC20 public tokenA;
ERC20 public tokenB;
function setUp() public {
tokenA = new MockERC20("Token A", "TKNA");
tokenB = new MockERC20("Token B", "TKNB");
liquidityMining = new LiquidityMiningHelper();
// Add target contracts for invariant testing
targetContract(address(liquidityMining));
targetContract(address(tokenA));
targetContract(address(tokenB));
}
function invariant_liquidityNeverNegative() public {
// Liquidity should never be negative
uint256 totalLiquidity = liquidityMining.getTotalLiquidity();
assertTrue(totalLiquidity >= 0);
}
function invariant_rewardsDistribution() public {
// Total rewards distributed should not exceed allocated rewards
uint256 totalDistributed = liquidityMining.getTotalDistributedRewards();
uint256 totalAllocated = liquidityMining.getTotalAllocatedRewards();
assertTrue(totalDistributed <= totalAllocated);
}
}
Integration Testing
Cross-Contract Testing:
contract IntegrationTest is Test {
Factory public factory;
LiquidityMiningHelper public liquidityMining;
Governance public governance;
address public owner = address(0x1);
address public user1 = address(0x2);
address public user2 = address(0x3);
function setUp() public {
vm.startPrank(owner);
// Deploy all contracts
factory = new Factory();
liquidityMining = new LiquidityMiningHelper();
governance = new Governance();
// Set up relationships
factory.setLiquidityMiningHelper(address(liquidityMining));
liquidityMining.setGovernance(address(governance));
vm.stopPrank();
}
function testFullTokenLifecycle() public {
// 1. Create token
vm.startPrank(user1);
vm.deal(user1, 1 ether);
address tokenAddress = factory.createToken{value: 0.001 ether}(
"Integration Token",
"INT",
"Integration test token",
"https://example.com/int.png",
300, // 3% creator fee
0 // Basic template
);
Template token = Template(tokenAddress);
vm.stopPrank();
// 2. Add liquidity
vm.startPrank(user2);
vm.deal(user2, 2 ether);
// Mint tokens for liquidity provision
token.mint{value: 1 ether}(user2, 1000 ether);
// Add liquidity to pool
liquidityMining.addLiquidity(
tokenAddress,
address(0), // ETH
1000 ether, // Token amount
1 ether // ETH amount
);
vm.stopPrank();
// 3. Verify liquidity mining rewards
uint256 userLPBalance = liquidityMining.getUserLPBalance(user2, tokenAddress);
assertTrue(userLPBalance > 0);
// 4. Fast forward time and claim rewards
vm.warp(block.timestamp + 1 days);
vm.startPrank(user2);
uint256 pendingRewards = liquidityMining.getPendingRewards(user2, tokenAddress);
assertTrue(pendingRewards > 0);
liquidityMining.claimRewards(tokenAddress);
vm.stopPrank();
// 5. Verify governance voting power
uint256 votingPower = governance.getVotingPower(user2);
assertTrue(votingPower > 0); // Should have voting power from LP tokens
}
}
API Testing
REST API Testing
Jest Test Setup:
// package.json
{
"devDependencies": {
"jest": "^29.0.0",
"supertest": "^6.0.0",
"@types/jest": "^29.0.0",
"@types/supertest": "^2.0.0"
},
"scripts": {
"test": "jest",
"test:api": "jest --testMatch='**/*.api.test.js'"
}
}
API Test Examples:
// tests/api.test.js
const request = require("supertest");
const BASE_URL =
process.env.API_BASE_URL || "https://api-sepolia.memetrade.com";
const API_KEY = process.env.MEMETRADE_API_KEY;
describe("MemeTrade API", () => {
const headers = {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
};
describe("GET /api/v1/tokens", () => {
test("should return paginated token list", async () => {
const response = await request(BASE_URL)
.get("/api/v1/tokens?page=1&limit=10")
.set(headers)
.expect(200);
expect(response.body).toHaveProperty("tokens");
expect(response.body).toHaveProperty("pagination");
expect(response.body.tokens).toBeInstanceOf(Array);
expect(response.body.tokens.length).toBeLessThanOrEqual(10);
// Verify token structure
if (response.body.tokens.length > 0) {
const token = response.body.tokens[0];
expect(token).toHaveProperty("address");
expect(token).toHaveProperty("name");
expect(token).toHaveProperty("symbol");
expect(token).toHaveProperty("price");
expect(token).toHaveProperty("marketCap");
}
});
test("should handle invalid pagination", async () => {
await request(BASE_URL)
.get("/api/v1/tokens?page=-1&limit=1000")
.set(headers)
.expect(400);
});
});
describe("GET /api/v1/tokens/:address", () => {
test("should return token details", async () => {
// Use a known test token address
const tokenAddress = "0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa";
const response = await request(BASE_URL)
.get(`/api/v1/tokens/${tokenAddress}`)
.set(headers)
.expect(200);
expect(response.body).toHaveProperty("address", tokenAddress);
expect(response.body).toHaveProperty("name");
expect(response.body).toHaveProperty("symbol");
expect(response.body).toHaveProperty("totalSupply");
expect(response.body).toHaveProperty("creator");
});
test("should return 404 for non-existent token", async () => {
const fakeAddress = "0x0000000000000000000000000000000000000000";
await request(BASE_URL)
.get(`/api/v1/tokens/${fakeAddress}`)
.set(headers)
.expect(404);
});
});
describe("POST /api/v1/trading/quote", () => {
test("should return valid quote", async () => {
const quoteRequest = {
tokenIn: "0x0000000000000000000000000000000000000000", // ETH
tokenOut: "0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa",
amountIn: "1000000000000000000", // 1 ETH
slippage: 0.01,
};
const response = await request(BASE_URL)
.post("/api/v1/trading/quote")
.set(headers)
.send(quoteRequest)
.expect(200);
expect(response.body).toHaveProperty("amountOut");
expect(response.body).toHaveProperty("priceImpact");
expect(response.body).toHaveProperty("minimumReceived");
expect(response.body).toHaveProperty("route");
// Verify numeric fields
expect(typeof response.body.amountOut).toBe("string");
expect(typeof response.body.priceImpact).toBe("number");
expect(response.body.priceImpact).toBeGreaterThanOrEqual(0);
});
});
});
Load Testing:
// tests/load.test.js
const request = require("supertest");
describe("API Load Testing", () => {
test("should handle concurrent requests", async () => {
const promises = [];
const concurrentRequests = 50;
for (let i = 0; i < concurrentRequests; i++) {
promises.push(
request(BASE_URL).get("/api/v1/tokens/trending").set(headers)
);
}
const responses = await Promise.allSettled(promises);
// Most requests should succeed
const successCount = responses.filter(
(r) => r.status === "fulfilled" && r.value.status === 200
).length;
expect(successCount).toBeGreaterThan(concurrentRequests * 0.8); // 80% success rate
});
});
WebSocket Testing
WebSocket Test Framework:
// tests/websocket.test.js
const WebSocket = require("ws");
describe("WebSocket API (Planned)", () => {
// Test cases for WebSocket API will be added once the API is implemented.
});
Frontend Testing
React Component Testing
Component Test Setup:
// setupTests.js
import "@testing-library/jest-dom";
import { TextEncoder, TextDecoder } from "util";
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
// Mock WebSocket
global.WebSocket = jest.fn(() => ({
send: jest.fn(),
close: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
}));
Component Tests:
// TokenPrice.test.tsx
import React from "react";
import { render, screen, waitFor } from "@testing-library/react";
import { TokenPrice } from "../components/TokenPrice";
// Mock the SDK
jest.mock("@memetrade/sdk", () => ({
MemeTrade: jest.fn().mockImplementation(() => ({
tokens: {
getStats: jest.fn().mockResolvedValue({
price: 0.000123,
volume24h: 50000,
marketCap: 123456,
}),
},
})),
}));
describe("TokenPrice Component", () => {
const tokenAddress = "0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa";
test("displays token price", async () => {
render(<TokenPrice tokenAddress={tokenAddress} />);
// Initially shows loading
expect(screen.getByText("Loading price...")).toBeInTheDocument();
// Wait for price to load
await waitFor(() => {
expect(screen.getByText("$0.000123")).toBeInTheDocument();
});
});
test("handles error state", async () => {
// Mock error
const { MemeTrade } = require("@memetrade/sdk");
MemeTrade.mockImplementation(() => ({
tokens: {
getStats: jest.fn().mockRejectedValue(new Error("API Error")),
},
}));
render(<TokenPrice tokenAddress={tokenAddress} />);
await waitFor(() => {
expect(screen.getByText("Price unavailable")).toBeInTheDocument();
});
});
});
E2E Testing with Playwright
Playwright Setup:
// playwright.config.js
module.exports = {
testDir: "./tests/e2e",
timeout: 30000,
use: {
baseURL: "http://localhost:3000",
headless: true,
screenshot: "only-on-failure",
},
projects: [
{ name: "chromium", use: { ...devices["Desktop Chrome"] } },
{ name: "firefox", use: { ...devices["Desktop Firefox"] } },
{ name: "webkit", use: { ...devices["Desktop Safari"] } },
],
};
E2E Test Examples:
// tests/e2e/token-creation.spec.js
import { test, expect } from "@playwright/test";
test.describe("Token Creation Flow", () => {
test("should create token successfully", async ({ page }) => {
await page.goto("/create");
// Fill form
await page.fill('[data-testid="token-name"]', "Test Token");
await page.fill('[data-testid="token-symbol"]', "TEST");
await page.fill(
'[data-testid="token-description"]',
"A test token for E2E testing"
);
// Upload image
await page.setInputFiles('[data-testid="token-image"]', "test-image.png");
// Set creator fee
await page.fill('[data-testid="creator-fee"]', "2.5");
// Submit form
await page.click('[data-testid="create-token-button"]');
// Wait for wallet connection (if needed)
// This would depend on your wallet integration
// Verify success
await expect(page.locator('[data-testid="success-message"]')).toBeVisible();
await expect(page.locator('[data-testid="token-address"]')).toBeVisible();
});
test("should show validation errors", async ({ page }) => {
await page.goto("/create");
// Try to submit empty form
await page.click('[data-testid="create-token-button"]');
// Check for validation errors
await expect(page.locator('[data-testid="name-error"]')).toContainText(
"Name is required"
);
await expect(page.locator('[data-testid="symbol-error"]')).toContainText(
"Symbol is required"
);
});
});
test.describe("Trading Flow", () => {
test("should execute trade", async ({ page }) => {
const tokenAddress = "0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa";
await page.goto(`/token/${tokenAddress}`);
// Check token page loads
await expect(page.locator('[data-testid="token-name"]')).toBeVisible();
await expect(page.locator('[data-testid="token-price"]')).toBeVisible();
// Enter trade amount
await page.fill('[data-testid="trade-amount"]', "0.1");
// Click buy button
await page.click('[data-testid="buy-button"]');
// Confirm transaction (mock wallet interaction)
await page.click('[data-testid="confirm-trade"]');
// Wait for transaction confirmation
await expect(page.locator('[data-testid="trade-success"]')).toBeVisible({
timeout: 30000,
});
});
});
Performance Testing
Contract Gas Optimization
Gas Testing:
contract GasTest is Test {
Factory public factory;
function setUp() public {
factory = new Factory();
}
function testTokenCreationGas() public {
uint256 gasBefore = gasleft();
factory.createToken{value: 0.001 ether}(
"Gas Test Token",
"GAS",
"Testing gas consumption",
"https://example.com/gas.png",
250,
0
);
uint256 gasUsed = gasBefore - gasleft();
// Assert gas usage is within expected range
assertTrue(gasUsed < 2_000_000, "Token creation uses too much gas");
console.log("Gas used for token creation:", gasUsed);
}
function testBatchOperationGas() public {
// Test gas efficiency of batch operations vs individual operations
// Individual operations
uint256 gasIndividual = 0;
uint256 gasBefore = gasleft();
// Operation 1
factory.updateFee(100);
uint256 gasAfter1 = gasleft();
gasIndividual += gasBefore - gasAfter1;
// Operation 2
gasBefore = gasleft();
factory.updateCreationFee(0.002 ether);
uint256 gasAfter2 = gasleft();
gasIndividual += gasBefore - gasAfter2;
// Batch operation
gasBefore = gasleft();
factory.batchUpdate(100, 0.002 ether);
uint256 gasBatch = gasBefore - gasleft();
// Batch should be more efficient
assertTrue(gasBatch < gasIndividual, "Batch operation should use less gas");
console.log("Individual operations gas:", gasIndividual);
console.log("Batch operation gas:", gasBatch);
console.log("Gas savings:", gasIndividual - gasBatch);
}
}
Load Testing Scripts
Artillery Load Testing:
# load-test.yml
config:
target: "https://api-sepolia.memetrade.com"
phases:
- duration: 60
arrivalRate: 10
- duration: 120
arrivalRate: 50
- duration: 60
arrivalRate: 100
headers:
Authorization: "Bearer {{ $processEnvironment.API_KEY }}"
Content-Type: "application/json"
scenarios:
- name: "Get token list"
weight: 40
flow:
- get:
url: "/api/v1/tokens?page={{ $randomInt(1, 10) }}&limit=20"
- name: "Get token details"
weight: 30
flow:
- get:
url: "/api/v1/tokens/{{ $randomString(42) }}"
- name: "Get trading quote"
weight: 20
flow:
- post:
url: "/api/v1/trading/quote"
json:
tokenIn: "0x0000000000000000000000000000000000000000"
tokenOut: "0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa"
amountIn: "{{ $randomInt(1000000000000000000, 10000000000000000000) }}"
slippage: 0.01
- name: "WebSocket connection"
weight: 10
engine: ws
flow:
- connect:
target: "wss://api-sepolia.memetrade.com/ws"
- send:
payload: |
{
"type": "subscribe",
"channel": "prices",
"tokens": ["0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa"]
}
- think: 30
Testnet Testing
Base Sepolia Testing
Faucet Integration:
// scripts/setup-testnet.js
const { ethers } = require("ethers");
async function setupTestnetAccount() {
const provider = new ethers.providers.JsonRpcProvider(
process.env.BASE_SEPOLIA_RPC_URL
);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
console.log("Test account:", wallet.address);
// Check ETH balance
const balance = await provider.getBalance(wallet.address);
console.log("ETH balance:", ethers.utils.formatEther(balance));
if (balance.lt(ethers.utils.parseEther("0.1"))) {
console.log("Low balance! Get testnet ETH from:");
console.log("https://bridge.base.org/");
console.log("https://faucet.quicknode.com/base/sepolia");
}
// Test factory interaction
const factory = new ethers.Contract(
"0x742d35Cc62D51C846fDa67F9e3c4b65e45E2F4Aa",
[
"function createToken(string,string,string,string,uint256,uint256) payable returns(address)",
],
wallet
);
try {
const tx = await factory.createToken(
"Test Token",
"TEST",
"Testnet testing token",
"https://example.com/test.png",
250, // 2.5% fee
0, // Basic template
{ value: ethers.utils.parseEther("0.001") }
);
console.log("Token creation tx:", tx.hash);
const receipt = await tx.wait();
console.log("Token created at block:", receipt.blockNumber);
} catch (error) {
console.error("Token creation failed:", error.message);
}
}
setupTestnetAccount().catch(console.error);
Automated Testing Pipeline:
// scripts/test-pipeline.js
const { execSync } = require("child_process");
async function runTestPipeline() {
console.log("๐งช Starting MemeTrade Test Pipeline...\n");
try {
// 1. Smart contract tests
console.log("๐ Running smart contract tests...");
execSync("forge test", { stdio: "inherit" });
console.log("โ
Smart contract tests passed\n");
// 2. API tests
console.log("๐ Running API tests...");
execSync("npm run test:api", { stdio: "inherit" });
console.log("โ
API tests passed\n");
// 3. Frontend tests
console.log("๐จ Running frontend tests...");
execSync("npm run test:frontend", { stdio: "inherit" });
console.log("โ
Frontend tests passed\n");
// 4. E2E tests
console.log("๐ญ Running E2E tests...");
execSync("npx playwright test", { stdio: "inherit" });
console.log("โ
E2E tests passed\n");
// 5. Load tests (optional)
if (process.env.RUN_LOAD_TESTS === "true") {
console.log("โก Running load tests...");
execSync("artillery run load-test.yml", { stdio: "inherit" });
console.log("โ
Load tests passed\n");
}
console.log("๐ All tests passed!");
} catch (error) {
console.error("โ Test pipeline failed:", error.message);
process.exit(1);
}
}
runTestPipeline();
CI/CD Testing
GitHub Actions Workflow
# .github/workflows/test.yml
name: Test Suite
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
smart-contracts:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
- name: Run smart contract tests
run: |
cd memetrade
forge test --gas-report
- name: Upload coverage
uses: codecov/codecov-action@v3
with:
file: ./coverage.json
api-tests:
runs-on: ubuntu-latest
services:
redis:
image: redis:alpine
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install dependencies
run: npm ci
- name: Run API tests
env:
MEMETRADE_API_KEY: ${{ secrets.TEST_API_KEY }}
BASE_SEPOLIA_RPC_URL: ${{ secrets.BASE_SEPOLIA_RPC_URL }}
run: npm run test:api
frontend-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install dependencies
run: npm ci
- name: Run frontend tests
run: npm run test:frontend
- name: Build application
run: npm run build
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- name: Install dependencies
run: npm ci
- name: Install Playwright
run: npx playwright install --with-deps
- name: Run E2E tests
env:
MEMETRADE_API_KEY: ${{ secrets.TEST_API_KEY }}
run: npx playwright test
- name: Upload test results
uses: actions/upload-artifact@v3
if: failure()
with:
name: playwright-report
path: playwright-report/
Best Practices
Testing Strategies
Test Pyramid:
โโโโโโโโโโโโโโโ
โ E2E Tests โ (Few, High-level, Slow)
โ 10% โ
โโโโโโโโโโโโโโโค
โ Integration โ (Some, Medium-level, Medium)
โ Tests 20% โ
โโโโโโโโโโโโโโโค
โ Unit Tests โ (Many, Low-level, Fast)
โ 70% โ
โโโโโโโโโโโโโโโ
Code Coverage Goals:
Smart contracts: >95%
APIs: >90%
Frontend components: >80%
E2E critical paths: 100%
Security Testing
Common Vulnerabilities to Test:
// Test for reentrancy
function testReentrancyProtection() public {
vm.expectRevert("ReentrancyGuard: reentrant call");
// Attempt reentrancy attack
}
// Test for overflow/underflow
function testSafeArithmetic() public {
// Test edge cases with SafeMath
}
// Test access controls
function testOnlyOwnerFunctions() public {
vm.expectRevert("Ownable: caller is not the owner");
// Try calling owner-only function as non-owner
}
// Test input validation
function testInputSanitization() public {
vm.expectRevert("Invalid input");
// Pass malicious input
}
Performance Benchmarks
Target Metrics:
API response time: <100ms (95th percentile)
WebSocket message latency: <50ms
Contract deployment: <500k gas
Token creation: <300k gas
Trade execution: <200k gas
Ready to test your integration? Start with the basic test setup and gradually add more comprehensive testing as your integration grows. Join our Discord #testing-support channel for help with specific testing scenarios.
Next Steps:
Last updated