Test Client Setup
Overview
This guide covers how to create and configure Brane.Tester clients for integration testing. Brane provides multiple ways to connect to test nodes, from simple one-liners to fully customized builder patterns.
connectTest() Factory Methods
The Brane interface provides static factory methods for quickly creating test clients. These methods are designed for common testing scenarios with sensible defaults.
Default Connection
The simplest way to connect uses Anvil at http://127.0.0.1:8545 with the default test key (account 0):
import sh.brane.rpc.Brane;
// Connect with all defaults
Brane.Tester tester = Brane.connectTest();This is equivalent to:
Brane.Tester tester = Brane.builder()
.rpcUrl("http://127.0.0.1:8545")
.signer(AnvilSigners.defaultKey())
.testMode(TestNodeMode.ANVIL)
.buildTester();With Custom Signer
Connect to the default Anvil URL with a specific test account:
import sh.brane.rpc.AnvilSigners;
// Use account at index 3
Signer signer = AnvilSigners.keyAt(3);
Brane.Tester tester = Brane.connectTest(signer);With Custom URL
Connect to a remote or custom-port Anvil instance:
// Remote Anvil instance
Brane.Tester tester = Brane.connectTest("http://192.168.1.100:8545");
// Custom local port
Brane.Tester tester = Brane.connectTest("http://127.0.0.1:9545");With Custom URL and Signer
import sh.brane.core.crypto.PrivateKeySigner;
Signer signer = new PrivateKeySigner("0x...");
Brane.Tester tester = Brane.connectTest("http://localhost:8545", signer);With Different Test Node
Connect to Hardhat or Ganache instead of Anvil:
import sh.brane.rpc.TestNodeMode;
import sh.brane.core.crypto.PrivateKeySigner;
Signer signer = new PrivateKeySigner("0x...");
Brane.Tester tester = Brane.connectTest(
"http://localhost:8545",
signer,
TestNodeMode.HARDHAT
);Method Reference
| Method | URL | Signer | Mode |
|---|---|---|---|
connectTest() | Default | Default key | ANVIL |
connectTest(Signer) | Default | Custom | ANVIL |
connectTest(String) | Custom | Default key | ANVIL |
connectTest(String, Signer) | Custom | Custom | ANVIL |
connectTest(String, Signer, TestNodeMode) | Custom | Custom | Custom |
Default URL: http://127.0.0.1:8545
TestNodeMode
TestNodeMode specifies which test node implementation you're connecting to. Each node uses different RPC method prefixes for its custom operations.
Available Modes
public enum TestNodeMode {
ANVIL("anvil_"), // Foundry's Anvil (recommended)
HARDHAT("hardhat_"), // Hardhat Network
GANACHE("evm_") // Truffle's Ganache
}RPC Method Prefixes
Each test node uses a different prefix for custom RPC methods:
| Operation | Anvil | Hardhat | Ganache |
|---|---|---|---|
| Mine blocks | anvil_mine | hardhat_mine | evm_mine |
| Set balance | anvil_setBalance | hardhat_setBalance | evm_setBalance |
| Impersonate | anvil_impersonateAccount | hardhat_impersonateAccount | evm_impersonateAccount |
When to Specify Mode
You only need to specify TestNodeMode when connecting to non-Anvil nodes:
// Anvil - mode is optional (default)
Brane.Tester tester = Brane.connectTest();
// Hardhat - must specify mode
Brane.Tester tester = Brane.connectTest(
"http://localhost:8545",
signer,
TestNodeMode.HARDHAT
);
// Ganache - must specify mode
Brane.Tester tester = Brane.connectTest(
"http://localhost:7545",
signer,
TestNodeMode.GANACHE
);Builder Pattern
For advanced configuration, use Brane.builder() with buildTester():
Brane.Tester tester = Brane.builder()
.rpcUrl("http://localhost:8545")
.signer(AnvilSigners.defaultKey())
.testMode(TestNodeMode.ANVIL)
.retries(5)
.buildTester();Builder Methods
| Method | Description | Default |
|---|---|---|
rpcUrl(String) | HTTP/HTTPS RPC endpoint | Required |
signer(Signer) | Transaction signer | Required for buildTester() |
testMode(TestNodeMode) | Test node type | ANVIL |
chain(ChainProfile) | Network-specific config | None |
retries(int) | Max retry attempts | 3 |
retryConfig(RpcRetryConfig) | Backoff timing | Defaults |
Build Methods
The builder provides three terminal methods:
// Read-only client (no signer required)
Brane.Reader reader = Brane.builder()
.rpcUrl("https://eth.example.com")
.buildReader();
// Signing client (signer required)
Brane.Signer signer = Brane.builder()
.rpcUrl("https://eth.example.com")
.signer(key)
.buildSigner();
// Test client (signer required)
Brane.Tester tester = Brane.builder()
.rpcUrl("http://localhost:8545")
.signer(key)
.buildTester();Advanced Configuration
import sh.brane.core.chain.ChainProfiles;
import sh.brane.rpc.RpcRetryConfig;
Brane.Tester tester = Brane.builder()
.rpcUrl("http://localhost:8545")
.signer(AnvilSigners.keyAt(0))
.testMode(TestNodeMode.ANVIL)
.chain(ChainProfiles.MAINNET)
.retries(5)
.retryConfig(RpcRetryConfig.builder()
.baseDelay(100)
.maxDelay(5000)
.build())
.buildTester();AnvilSigners
AnvilSigners provides access to Anvil's 10 pre-funded test accounts. Each account is funded with 10,000 ETH when Anvil starts.
Getting Test Keys
import sh.brane.rpc.AnvilSigners;
// Default key (account 0) - most commonly used
Signer signer = AnvilSigners.defaultKey();
// Specific account by index (0-9)
Signer account3 = AnvilSigners.keyAt(3);
// Number of available accounts
int count = AnvilSigners.count(); // 10Default Addresses
The 10 pre-funded accounts and their addresses:
| Index | Address |
|---|---|
| 0 | 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 |
| 1 | 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 |
| 2 | 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC |
| 3 | 0x90F79bf6EB2c4f870365E785982E1f101E93b906 |
| 4 | 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 |
| 5 | 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc |
| 6 | 0x976EA74026E726554dB657fA54763abd0C3a0aa9 |
| 7 | 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955 |
| 8 | 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f |
| 9 | 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720 |
Key Derivation
These keys are derived from the well-known test mnemonic:
test test test test test test test test test test test junkUsing derivation path m/44'/60'/0'/0/i where i is the account index.
Using Multiple Accounts
// Iterate over all accounts
for (int i = 0; i < AnvilSigners.count(); i++) {
Signer signer = AnvilSigners.keyAt(i);
System.out.println("Account " + i + ": " + signer.address());
}
// Use different accounts for different roles
Signer deployer = AnvilSigners.keyAt(0);
Signer alice = AnvilSigners.keyAt(1);
Signer bob = AnvilSigners.keyAt(2);Complete Example
import sh.brane.rpc.Brane;
import sh.brane.rpc.AnvilSigners;
import sh.brane.rpc.SnapshotId;
import sh.brane.core.types.Address;
import sh.brane.core.types.Wei;
public class TestSetupExample {
public static void main(String[] args) {
// 1. Create tester with builder for full control
Brane.Tester tester = Brane.builder()
.rpcUrl("http://127.0.0.1:8545")
.signer(AnvilSigners.keyAt(0))
.retries(3)
.buildTester();
// 2. Take snapshot for test isolation
SnapshotId snapshot = tester.snapshot();
try {
// 3. Get additional test accounts
Signer alice = AnvilSigners.keyAt(1);
Signer bob = AnvilSigners.keyAt(2);
// 4. Fund a test address
Address testAddr = new Address("0x1234567890123456789012345678901234567890");
tester.setBalance(testAddr, Wei.fromEther(new java.math.BigDecimal("100")));
// 5. Run test operations
// ...
} finally {
// 6. Restore state for next test
tester.revert(snapshot);
}
}
}Prerequisites
Before using Brane.Tester, start your test node:
Anvil (Recommended)
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup
# Start Anvil
anvilHardhat
npx hardhat nodeGanache
npx ganache --port 7545