本指南将带你了解如何使用Bankrun测试你的Solana程序
测试你的 Solana 程序是开发过程中的关键部分,以确保你的程序按预期运行,甚至可以加快你的开发。本指南将带你了解如何使用 Bankrun 测试你的 Solana 程序,Bankrun 是一个超级快速的 Solana 程序测试运行器。
大多数 Solana 测试使用 Mocha 框架 编写测试,并使用 Chai 进行断言。不过,你可以使用任何你熟悉的测试框架。在本指南中,我们将看看 Jest 和 Bankrun。使用 Bankrun,你可以将测试的速度提升近 10 倍,获得修改程序时间的能力,并编写自定义账户数据。
有一些预设将为你的 Solana 程序设置一个基本的测试环境。这些预设例如:
npx create-solana-dapp my-dapp
create-solana-dapp
将为你设置一个包含各种配置选项的 Solana Web 项目,包括 Next.js 或 React 客户端、Tailwind UI 库和一个简单的 Anchor 程序。测试使用 Jest 编写,可以通过 anchor test
命令运行。
npx create-solana-game my-game
create-solana-game
将为你设置一个包含 Jest、Mocha 和 Bankrun 测试的 Solana 游戏项目,以及一个使用 Solana Wallet 适配器的 NextJS 应用和一个额外的 Unity 游戏引擎客户端。Mocha 和 Bankrun 测试都可以通过 anchor test
命令运行。
你还可以在 Solana Program Examples 中找到许多测试示例。
使用 Anchor 框架,你可以运行 anchor test
命令以执行 anchor.toml
文件中的预配置 test
命令。
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
这将在 tests 目录中使用 ts-mocha
命令运行测试,超时时间为 1,000,000 毫秒。
这里的 Anchor 功能是启动一个本地验证者,从你的 Anchor 工作区部署程序,并在 Anchor.toml
中定义的网络上运行测试。
提示:你也可以运行
anchor test --detach
让验证者在测试完成后继续运行,这样你就可以在 Solana Explorer 中检查你的交易。
你还可以在 anchor.toml
文件中定义你自己的测试命令。例如,你可以首先在本地验证者上运行 mocha 测试,然后使用 bankrun 运行 jest 测试,通过 &&
将它们组合:
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts && yarn run jest"
这将首先运行 mocha 测试,然后运行 jest 测试。
你也可以定义你自己的测试命令。例如:
super_test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 only_super_test.ts"
jest_tests = "yarn test"
这些你将使用以下命令运行:
anchor run super_test
anchor run jest_tests
不过需要注意的是,在这种情况下,anchor 不会为你启动一个本地验证者。因此,你需要将程序部署到本地集群,或在公共测试网络上运行它们。另外,当通过
anchor test
命令运行时,Anchor 环境变量才会可用,而通过yarn test
例如运行时则不可用。
在这一部分,我们将学习如何从 Mocha 迁移到 Jest。Jest 是一个类似于 Mocha 的 JavaScript 测试框架。它已经集成了测试运行器,因此你不再需要使用 Chai。
首先,你需要安装 Jest:
然后你在 package.json
中添加一个新命令:
{
"scripts": {
"test": "jest"
}
}
然后你可以使用以下命令运行测试:
由于我们想用 Typescript 运行测试,因此需要安装 ts-jest
包,还需要创建一个 Jest 配置文件:
yarn add --dev ts-jest @jest/globals @types/jest
yarn ts-jest config:init
这将在你的项目中创建一个 jest.config.js
文件。现在你可以更新你的 Anchor.toml
文件以运行 Jest 测试:
SyntaxError: Cannot use import statement outside a module
jest.config.js
文件中添加以下内容: module.exports = {
transform: {
"^.+\\.tsx?$": "ts-jest",
},
testEnvironment: "node",
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node"],
};
jest.config.js
文件中设置超时: module.exports = {
testTimeout: 10000,
};
或者你可以为单个测试设置超时:
test("test name", async () => {
// your test code
}, 10000);
anchor test
或 anchor run test
运行测试的情况下使用 AnchorProvider。只需更新你的 Anchor.toml 以运行 Jest 测试,yarn test
将在 Anchor 环境中运行,并设置所有环境变量。你还可以使用 Solana Bankrun 代替 solana-test-validator
。它的功能类似于本地验证者,但更轻便且更快。一些非常有用的功能是 编写自定义账户数据 和 时间旅行,使得测试基于时间的程序和依赖特定账户数据的程序变得更加容易。
要使用 Bankrun 和 Bankrun Anchor,你需要将其添加到你的 package.json
:
yarn add solana-bankrun anchor-bankrun
要将 Mocha Anchor 测试切换到 Bankrun Anchor 测试,你只需要将提供者更改为 BankrunProvider
,并在每个测试文件中使用 startAnchor
创建上下文:
// ... imports here
describe('My test', () => {
test('Test allocate counter + increment tx', async () => {
const context = await startAnchor(".", [], []);
const client = context.banksClient;
const provider = new BankrunProvider(context);
anchor.setProvider(provider);
// ... testing logic
}
}
startAnchor
将自动将你的程序从 Anchor 工作区添加到 Bankrun 银行。你还可以通过在 startAnchor
函数中传递它们, 添加额外的账户和程序 到银行。不过,与在本地验证者上运行测试相比,还是有一些不同的地方,我们将在下一部分讨论。
Bankrun 使用 BanksServer(一个简化版的 Solana 的银行,用于处理交易和管理账户)和 BanksClient 来模拟 Solana 网络,使得可以使用时间操作和动态账户数据设置等高级测试功能。与 solana-test-validator
不同,bankrun 允许通过与网络状态的本地实例进行高效测试,因此非常适合在不需要完整验证器的情况下测试 Solana 程序。交易的行为非常相似,但与本地验证器有一些区别:
startAnchor
函数中传入一个额外的账户来创建一个。 let secondKeypair: Keypair = new anchor.web3.Keypair();
context = await startAnchor(
"",[],
[
{
address: secondKeypair.publicKey,
info: {
lamports: 1_000_000_000, // 1 SOL 等价
data: Buffer.alloc(0),
owner: SYSTEM_PROGRAM_ID,
executable: false,
},
},
]
);
provider = new BankrunProvider(context);
由于 Bankrun 直接在银行上工作,你不需要确认你的交易。因此 connection.confirmTransaction()
函数将不可用。你可以直接省略它。
虽然你仍然可以使用 connection.getAccount
来检索账户数据,但在 bankrun 框架中,首选方法是使用 client.getAccount
,它返回一个 Promise<Account>
。这种方法与测试框架的设计更为一致。然而,如果你希望在其余的 Solana 代码库中保持一致,你可以继续使用 connection.getAccount。选择最适合你具体用例的方法。
await client.getAccount(playerPDA).then(info => {
const decoded = program.coder.accounts.decode(
"playerData",
Buffer.from(info.data),
);
console.log("玩家账户信息", JSON.stringify(decoded));
expect(decoded).toBeDefined();
expect(parseInt(decoded.energy)).toEqual(99);
});
默认情况下,当使用 program.function.rpc()
时,交易将自动使用 provider.wallet
密钥对进行签署。如果你想用其他密钥对签署交易,可以创建一个第二个提供者,然后使用那个提供者用其他密钥对签署交易。
let secondKeypair: Keypair = new anchor.web3.Keypair();
let context = await startAnchor(
"",[],
[
{
address: secondKeypair.publicKey,
info: {
lamports: 1_000_000_000,
data: Buffer.alloc(0),
owner: SYSTEM_PROGRAM_ID,
executable: false,
},
},
]
);
beneficiaryProvider = new BankrunProvider(context);
beneficiaryProvider.wallet = new NodeWallet(secondKeypair);
secondProgram = new Program<Vesting>(IDL as Vesting, beneficiaryProvider);
你还可以将 Bankrun 用于 原生程序。主要区别是你使用 start
而不是 startAnchor
来启动 Bankrun 银行,然后可以使用 client
与银行进行交互。
const context = await start(
[{ name: "counter_solana_native", programId: PROGRAM_ID }],
[],
);
const client = context.banksClient;
你可以使用 await client.processTransaction(tx)
来代替 program.instruction().rpc()
。
在 Solana 程序示例中,你可以找到一个 完整的原生 Bankrun 示例。
如果在使用 Bankrun 发送交易时遇到 Unknown action 'undefined'
错误,你可能尝试发送两个相同的交易,且使用相同的区块哈希。在发送第二个交易之前请求一个新的最近区块哈希,或者在你的指令中添加一些种子或参数,以确保它们会产生不同的交易哈希。
如果遇到 Clock handle timeout
错误,你只需重启终端并重新运行测试即可。
测试你的 Solana 程序对于确保其按预期运行至关重要。Bankrun 提供了一个轻量和快速的替代方案,使你的测试速度提高到 10 倍。它支持自定义账户数据和时间旅行等强大功能,这可以显著增强你的测试能力。此外,Jest 是撰写测试的良好替代选择,并且可以轻松与 Bankrun 集成。
然而,需要注意一些使用 Bankrun 相较于本地验证器的缺点:
尽管存在这些缺点,Bankrun 仍然是一个有价值的工具,可以极大地改善你的开发工作流程。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!