name: test-smart-contracts description: 测试Algorand智能合约的模式,使用生成的客户端和algorandFixture。在编写智能合约测试、设置测试固定装置和部署、调试失败的测试、测试多用户场景或询问E2E与单元测试时使用。强烈的触发词包括“我该如何测试我的合约”、“algorandFixture”、“测试失败”、“LocalNet测试”、“vitest设置”、“为合约提供资金”。
测试智能合约
使用algorandFixture和生成的类型化客户端编写Algorand智能合约的集成测试。
默认:集成测试(E2E)
**除非用户明确请求单元测试,否则始终编写集成测试。**集成测试针对LocalNet运行并测试真实的合约行为。
测试框架:支持Vitest(默认)和Jest。以下示例使用Vitest语法,但Jest等效物同样适用。
文件命名
- 集成测试:
contract.algo.e2e.spec.ts - 单元测试(仅在请求时):
contract.algo.spec.ts
规范示例
学习和适应:devportal-code-examples/contracts/HelloWorld
import { Config } from '@algorandfoundation/algokit-utils'
import { algorandFixture } from '@algorandfoundation/algokit-utils/testing'
import { Address } from 'algosdk'
import { beforeAll, beforeEach, describe, expect, test } from 'vitest'
import { MyContractFactory } from '../artifacts/clients/MyContract/MyContractClient'
describe('MyContract', () => {
const localnet = algorandFixture()
beforeAll(() => {
Config.configure({ debug: true })
})
// 10秒超时:LocalNet需要时间处理交易和确认区块
beforeEach(localnet.newScope, 10_000)
const deploy = async (account: Address) => {
const factory = localnet.algorand.client.getTypedAppFactory(MyContractFactory, {
defaultSender: account,
})
const { appClient } = await factory.deploy({
onUpdate: 'append',
onSchemaBreak: 'append',
suppressLog: true,
})
return { client: appClient }
}
test('should call method and verify result', async () => {
const { testAccount } = localnet.context
const { client } = await deploy(testAccount)
const result = await client.send.myMethod({ args: { value: 42n } })
expect(result.return).toBe(42n)
})
})
如何进行
- 定位生成的客户端 在
artifacts/clients/<ContractName>/<ContractName>Client.ts - 导入工厂(例如,
MyContractFactory)- 不是直接导入客户端 - 使用部署助手模式 如上所示
- **通过
client.send.methodName()或client.newGroup().methodName().send()调用方法
重要规则
| 规则 | 详情 |
|---|---|
| 使用newGroup()进行链式操作 | client.newGroup().method1().method2().send() |
| 结构返回是元组 | const [id, name] = result.return as [bigint, string] |
| 为BoxMap提供资金 | 在box操作之前向client.appAddress发送支付 |
| 在本地状态之前选择加入 | await client.newGroup().optIn.optInToApplication().send() |
常见模式
为box存储提供资金给合约
await localnet.algorand.send.payment({
amount: (1).algo(),
sender: testAccount,
receiver: client.appAddress,
})
同一合约上的多个用户
// 创建并为第二个用户提供资金
const user2 = localnet.algorand.account.random()
await localnet.algorand.send.payment({
amount: (5).algo(),
sender: testAccount,
receiver: user2.addr,
})
// 使用不同的发送者获取相同应用程序的客户端
const client2 = factory.getAppClientById({
appId: client.appId,
defaultSender: user2.addr,
})
Box引用
import { ABIUintType } from 'algosdk'
function createBoxReference(appId: bigint, prefix: string, key: bigint) {
const uint64Type = new ABIUintType(64)
const encodedKey = uint64Type.encode(key)
const boxName = new Uint8Array([...new TextEncoder().encode(prefix), ...encodedKey])
return { appId, name: boxName }
}
await client.send.setBoxMap({
args: { key: 1n, value: 'hello' },
boxReferences: [createBoxReference(client.appId, 'boxMap', 1n)],
})
参考
- 规范示例 - 来自algorandfoundation仓库的完整模式
- 单元测试指南 - 仅在用户请求单元测试时使用
- devportal-code-examples