首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(1)简介

对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(1)简介

在本教程中,将学习测试驱动开发的概念,了解如何在 Golang 中应用此方法为 Hyperledger Fabric                    v0.6 编写链代码。
通常,对链代码执行单元测试很麻烦,因为您需要先将链代码部署到 Docker                容器中的区块链网络中,以便访问底层区块链基础架构,比如账本、交易信息等。本教程将展示一个替代方法,通过此方法,您可以使用我的                CustomMockStub(它扩展了 shim 包中提供的 MockStub)                轻松对链代码执行单元测试。
本教程的示例还演示了如何在链代码中获得非确定性函数,以及如何对这些非确定性函数进行测试。
前提条件我们将继续介绍本教程系列的  中介绍的住房贷款申请用例。
  • 您应该已经熟悉第 1 部分中介绍的链代码的基本特征。
  • 还应已使用 Hyperledger Fabric 的 v0.6 分支设置了您的 go 链代码开发环境,如第 1 部分所述。
请参阅本教程底部的 “可下载资源” 来下载本教程中的所有代码示例,以及 CustomMockStub 实现。
链代码是什么?在 IBM Cloud 上开发-- 免费试用 30 天您可以获得 2GB 运行时和容器内存,配置最多 10 个云服务,以及获得免费的服务台支持。,开始使用免费的  构建和测试区块链网络。它使用了最新的                    Hyperledger Fabric v1.0 架构。
进一步了解  和  的优点。

链代码(也称为智慧合同)是一组使用编程语言(比如 Golang 或                Java)编写的业务规则/逻辑,它规定了区块链网络中的不同参与者如何相互交易。
测试驱动开发是什么?测试驱动开发(或 TDD)是一种开发方法,要求开发人员在编写实际的实现代码之前                编写一个测试。测试驱动开发改变了您的关注点。无需考虑如何实现代码,只需考虑如何验证代码。
大体上讲,TDD 包含 3 个阶段,您将循环执行这些阶段,直到所有任务需求都得到满足:
  • 红色:在缺少任何实现代码的情况下编写一个测试。运行此测试,该测试将以失败告终。
  • 绿色:编写获得通过的测试所需的最少代码量。这一步中编写的代码通常不是最佳的,也没有可靠的功能。
  • 重构:这里可以采用两种途径。如果第 2 步中编写的代码不需要任何重大重构,则返回到第 1                    步并编写下一个测试。另一方面,如果第 2                    步中编写的代码需要对结构、功能、性能等进行重构,则编写一个新测试来揭示代码中的缺陷,然后重构该代码来通过测试。
因为 TDD 采用了一种结构化方式将问题说明分解为测试形式的更小组成部分,所以带来了以下好处:
  • 代码井然有序、设计精良且容易测试
  • 已证实您的代码能按预期运行
  • 更快地获得开发反馈
  • 高质量代码
关于 Golang 测试库和 MockStub区块链开发人员推荐阅读内容借助  内的 developerWorks                    教程、课程、博客和社区支持,提高您的开发技能。

本教程使用 Golang 提供的原生测试库来编写测试。可以使用包测试来对 Go 包执行自动化测试。测试包类似于测试运行器,可使用                go test 命令进行调用。
我们需要一种方式来为对链代码开发中广泛使用的 shim.ChaincodeStubInterface 的调用创建桩代码                (stub)。所幸,shim 包包含 MockStub 实现,在单元测试期间可使用它为实际链代码中的                ChaincodeStubInterface 创建桩代码。
尽管 MockStub 包含 Hyperledger Fabric v0.6 中的大部分常用函数的实现,但不幸的是,MockStub                没有实现其他一些方法,比如                ReadCertAttribute。因为大多数链代码都使用此方法根据交易证书检索属性来执行访问控制,所以能为此方法创建桩代码并对我们的链代码执行全面单元测试很重要。所以我编写了一个自定义                MockStub,它通过实现一些未实现的方法并将现有方法委托给 shim.MockStub 来扩展 shim.MockStub 功能。
清单 1. CustomMockStub                实现的代码段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package shim

import (
    "github.com/golang/protobuf/ptypes/timestamp"
    "github.com/hyperledger/fabric/core/chaincode/shim/crypto/attr"
)

type CustomMockStub struct {
    stub           *MockStub
    CertAttributes map[string][]byte
}

// Constructor to initialise the CustomMockStub
func NewCustomMockStub(name string, cc Chaincode, attributes map[string][]byte) *CustomMockStub {
    s := new(CustomMockStub)
    s.stub = NewMockStub(name, cc)
    s.CertAttributes = attributes
    return s
}

func (mock *CustomMockStub) ReadCertAttribute(attributeName string) ([]byte, error) {
    return mock.CertAttributes[attributeName], nil
}

func (mock *CustomMockStub) GetState(key string) ([]byte, error) {
    return mock.stub.GetState(key)
}

func (mock *CustomMockStub) GetTxID() string {
    return mock.stub.GetTxID()
}

func (mock *CustomMockStub) MockInit(uuid string, function string, args []string) ([]byte, error) {
    mock.stub.args = getBytes(function, args)
    mock.MockTransactionStart(uuid)
    bytes, err := mock.stub.cc.Init(mock, function, args)
    mock.MockTransactionEnd(uuid)
    return bytes, err
}

func (mock *CustomMockStub) MockInvoke(uuid string, function string, args []string) ([]byte, error) {
    mock.stub.args = getBytes(function, args)
    mock.MockTransactionStart(uuid)
    bytes, err := mock.stub.cc.Invoke(mock, function, args)
    mock.MockTransactionEnd(uuid)
    return bytes, err
}

func (mock *CustomMockStub) MockQuery(function string, args []string) ([]byte, error) {
    mock.stub.args = getBytes(function, args)
    // no transaction needed for queries
    bytes, err := mock.stub.cc.Query(mock, function, args)
    return bytes, err
}

func (mock *CustomMockStub) PutState(key string, value []byte) error {
    return mock.stub.PutState(key, value)
}

func (mock *CustomMockStub) MockTransactionStart(txid string) {
    mock.stub.MockTransactionStart(txid)
}

func (mock *CustomMockStub) MockTransactionEnd(uuid string) {
    mock.stub.MockTransactionEnd(uuid)
}




CustomMockStub 包含对 MockStub 的引用,而且有一个将用于                ReadCertAttribute 方法中的属性图。我还重写了                MockInit、MockQuery 和 MockInvoke                方法,以便在调用链代码时传入我的 CustomMockStub。
返回列表