使用Brownie框架测试Vyper智能合约

使用Brownie框架测试Vyper智能合约

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:

  1. accounts:提供对本地账户的访问
  2. 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

高级测试技巧

  1. 隔离测试:使用pytest.mark装饰器来隔离测试,避免状态污染
  2. Gas消耗分析:Brownie可以自动记录每个交易的gas消耗
  3. 覆盖率报告:生成测试覆盖率报告,确保测试完整性
  4. 参数化测试:使用pytest.mark.parametrize进行多参数测试

最佳实践

  1. 为每个合约功能编写独立的测试用例
  2. 测试应包括正常情况和边界情况
  3. 对合约的所有修改操作都应测试回滚情况
  4. 定期检查测试覆盖率,确保关键功能都被覆盖
  5. 在CI/CD流程中集成测试

通过Brownie框架,开发者可以方便地编写全面的测试用例,确保Vyper智能合约的安全性和可靠性。测试驱动开发(TDD)方法特别适合智能合约开发,可以显著减少部署后的问题。

vyper vyper 项目地址: https://gitcode.com/gh_mirrors/vyp/vyper

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邬颖舒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值