使用Brownie框架测试Vyper智能合约
vyper 项目地址: https://gitcode.com/gh_mirrors/vyp/vyper
概述
在区块链智能合约开发中,测试是确保合约安全性和功能正确性的关键环节。本文将介绍如何使用Brownie框架来测试Vyper编写的智能合约。Brownie是一个基于Python的开发框架,它集成了pytest测试工具,为智能合约测试提供了便捷的解决方案。
环境准备
在开始测试之前,需要确保已经正确安装了Brownie框架。安装完成后,可以通过以下步骤初始化一个新的Brownie项目:
mkdir my_project && cd my_project
brownie init
这个命令会创建一个标准的项目结构,其中包含:
contracts/
目录:存放Vyper合约源代码tests/
目录:存放测试脚本scripts/
目录:存放部署脚本reports/
目录:存放测试报告
编写基础测试
让我们从一个简单的存储合约开始,演示如何编写基础测试用例。
示例合约
# storage.vy
storedData: public(int256)
@external
def __init__(_initialValue: int256):
self.storedData = _initialValue
@external
def set(_value: int256):
self.storedData = _value
测试脚本
# tests/test_storage.py
import pytest
INITIAL_VALUE = 4
@pytest.fixture
def storage_contract(Storage, accounts):
# 部署合约,传入初始值作为构造函数参数
yield Storage.deploy(INITIAL_VALUE, {'from': accounts[0]})
def test_initial_state(storage_contract):
# 测试构造函数是否正确设置了初始值
assert storage_contract.storedData() == INITIAL_VALUE
def test_set(storage_contract, accounts):
# 测试set函数是否能正确修改存储值
storage_contract.set(10, {'from': accounts[0]})
assert storage_contract.storedData() == 10
storage_contract.set(-5, {'from': accounts[0]})
assert storage_contract.storedData() == -5
在这个测试脚本中,我们使用了Brownie提供的两个重要fixture:
accounts
:提供对本地账户的访问Storage
:动态命名的fixture,用于部署合约
测试事件
智能合约中的事件是重要的日志机制,下面我们扩展存储合约,添加事件功能并测试它。
扩展后的合约
# advanced_storage.vy
event ValueChanged:
setter: indexed(address)
value: int256
storedData: public(int256)
locked: public(bool)
@external
def __init__(_initialValue: int256):
self.storedData = _initialValue
self.locked = False
@external
def set(_value: int256):
assert _value >= 0, "No negative values"
assert not self.locked, "Storage is locked when 100 or more is stored"
if _value >= 100:
self.locked = True
self.storedData = _value
log ValueChanged(msg.sender, _value)
@external
def reset():
self.locked = False
self.storedData = 0
事件测试
def test_events(adv_storage_contract, accounts):
tx1 = adv_storage_contract.set(10, {'from': accounts[0]})
tx2 = adv_storage_contract.set(20, {'from': accounts[1]})
tx3 = adv_storage_contract.reset({'from': accounts[0]})
# 验证事件内容
assert len(tx1.events) == 1
assert tx1.events[0]['value'] == 10
assert tx1.events[0]['setter'] == accounts[0]
assert len(tx2.events) == 1
assert tx2.events[0]['setter'] == accounts[1]
assert not tx3.events # reset操作不产生事件
测试交易回滚
在智能合约中,某些条件下交易应该回滚。Brownie提供了reverts
上下文管理器来测试这种情况。
回滚测试示例
def test_failed_transactions(adv_storage_contract, accounts):
# 测试负数输入应该回滚
with brownie.reverts("No negative values"):
adv_storage_contract.set(-10, {"from": accounts[1]})
# 测试锁定后修改值应该回滚
adv_storage_contract.set(150, {"from": accounts[1]})
with brownie.reverts("Storage is locked when 100 or more is stored"):
adv_storage_contract.set(10, {"from": accounts[1]})
# 测试解锁后可以正常修改
adv_storage_contract.reset({"from": accounts[1]})
adv_storage_contract.set(10, {"from": accounts[1]})
assert adv_storage_contract.storedData() == 10
高级测试技巧
- 隔离测试:使用
pytest.mark
装饰器来隔离测试,避免状态污染 - Gas消耗分析:Brownie可以自动记录每个交易的gas消耗
- 覆盖率报告:生成测试覆盖率报告,确保测试完整性
- 参数化测试:使用
pytest.mark.parametrize
进行多参数测试
最佳实践
- 为每个合约功能编写独立的测试用例
- 测试应包括正常情况和边界情况
- 对合约的所有修改操作都应测试回滚情况
- 定期检查测试覆盖率,确保关键功能都被覆盖
- 在CI/CD流程中集成测试
通过Brownie框架,开发者可以方便地编写全面的测试用例,确保Vyper智能合约的安全性和可靠性。测试驱动开发(TDD)方法特别适合智能合约开发,可以显著减少部署后的问题。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考