Board logo

标题: 对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(3)实现 [打印本页]

作者: look_w    时间: 2018-6-18 13:44     标题: 对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(3)实现

我们采用测试驱动开发来实现 sample_chaincode.go 文件中的 CreateLoanApplication 方法。
要求清单 3. 第一个测试的代码
1
2
3
4
5
6
7
8
9
func TestCreateLoanApplication (t *testing.T) {
    fmt.Println("Entering TestCreateLoanApplication")
    attributes := make(map[string][]byte)
    //Create a custom MockStub that internally uses shim.MockStub
    stub := shim.NewCustomMockStub("mockStub", new(SampleChaincode), attributes)
    if stub == nil {
        t.Fatalf("MockStub creation failed")
    }
}




如清单 3 所示,所有测试函数都以 “Test” 关键字开头,以便 Golang 测试包可以识别并运行这些函数。测试函数接受                testing.T 参数,该参数将提供对可用于编写测试的帮助器方法的访问。
依据清单 2 中所示的要求,CreateLoanApplication 方法应接受                ChaincodeStubInterface 作为其参数。因为 Hyperledger Fabric 在运行时会将                ChaincodeStubInterface 的实际实例传入 Query/Invoke/Init                方法中,所以您需要模拟 ChaincodeStubInterface 来实现单元测试。
在清单 3 中,第 5 行创建了一个新的                CustomMockStub,该函数接受名称、(您打算实现的)SampleChaincode                对象和一个属性图作为参数。这里创建的桩代码是 前面讨论过的 一段自定义模拟桩代码。
现在从包含 sample_chaincode_test.go 文件的 root 文件夹运行 go test                来执行此测试。您的输出应类似于:
1 bash-3.2$ go test
2 can't load package: package .:
3 sample_chaincode.go:1:1:1 expected 'package', found 'EOF'




和预期一样,测试失败了,因为 sample_chaincode.go                    文件是空的,甚至连包语句都没有。这表示测试处于红色阶段。
现在我们来编写通过此测试所需的最少量代码。将下面这行添加到 sample_chaincode.go 文件:
清单 4. 为了通过测试而需要向 sample_chaincode.go                添加的最少代码
1
package main




再次运行测试。测试失败并抛出以下错误:
1 ./sample_chaincode_test.go:18: undefined: SampleChaincode




测试失败是因为,sample_chaincode.go 文件没有定义 SampleChaincode。
让我们将此代码添加到 sample_chaincode.go 文件中:
清单 5. 向 sample_chaincode.go                添加另一段代码
1
2
type SampleChaincode struct {
}




再次运行测试。它仍将失败并抛出以下错误:
1 ./sample_chaincode_test.go:16: cannot use new (SampleChaincode)
2 (type *SampleChaincode) as type shim.Chaincode in argument to
3 shim.NewMockStub:
4        *SampleChaincode does not implement shim.Chaincode
5 (missing Init method)




测试失败是因为 CustomMockStub 要求 SampleChaincode 实现                    Init、Query 和 Invoke 方法,然后才会将其视为                shim.Chaincode 类型的实例。
现在将以下代码添加到 sample_chaincode.go:
清单 6. 向 sample_chaincode.go                添加另一段代码
1
2
3
4
5
6
7
8
9
10
11
func (t *SampleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    return nil, nil
}

func (t *SampleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    return nil, nil
}

func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
    return nil, nil
}




再次运行测试时,测试通过了。这是测试的绿色阶段。
1 bash-3.2$ go test
2 Entering TestCreateLoanApplication
3 2017/02/22 19:10:08 MockStub( mockStub &{} )
4 PASS




将 CreateLoanApplication 方法添加到                sample_chaincode.go:
清单 7. 将 CreateLoanApplication 方法添加到                    sample_chaincode.go
1
2
3
4
func CreateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
    fmt.Println("Entering CreateLoanApplication")
    return nil, nil
}




添加以下测试,以确保从 CreateLoanApplication 方法返回了一个验证错误来响应空输入参数。
清单 8. 添加针对验证错误的测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func TestCreateLoanApplicationValidation(t *testing.T) {
    fmt.Println("Entering TestCreateLoanApplicationValidation")
    attributes := make(map[string][]byte)
    stub := shim.NewCustomMockStub("mockStub", new(SampleChaincode), attributes)
    if stub == nil {
        t.Fatalf("MockStub creation failed")
    }

    stub.MockTransactionStart("t123")
    _, err := CreateLoanApplication(stub, []string{})
    if err == nil {
        t.Fatalf("Expected CreateLoanApplication to return validation error")
    }
    stub.MockTransactionEnd("t123")
}




请注意 stub.MockTransactionStart(“t123”) 和 stub.MockTransactionStop(“t123”)                调用。因为写入账本的任何信息都需要位于交易上下文中,所以测试必须在调用 CreateLoanApplication 方法之前启动交易,因为                CreateLoanApplication 方法会将贷款申请保存到账本中。然后必须结束具有相同 ID 的交易,以表明交易完成。
使用 go test 运行测试。
1 bash-3.2$ go test
2 Entering TestCreateLoanApplication
3 2017/02/22 22:55:52 MockStub( mockStub &{} )
4 Entering CreateLoanApplication
5 --- FAIL: TestCreateLoanApplicationValidation (0.00s)
6         sample_chaincode_test.go:35: Expected CreateLoanApplication to
          return validation error
7 FAIL
8 exit status 1




跟预期一样,测试失败了。现在向 sample_chaincode.js 添加通过测试所需的最少量代码:
清单 9. 为了通过测试而需要向 sample_chaincode.js                添加的最少量代码
1
2
3
4
func CreateLoanApplication(stub shim.ChaincodeStubInterface, args []string) ([]byte, error) {
    fmt.Println("Entering CreateLoanApplication")
    return nil, errors.New(“Expected atleast two arguments for loan application creation”)
}




再次使用 go test 运行测试。
1 bash-3.2$ go test
2 Entering TestCreateLoanApplication
3 2017/02/22 23:02:52 MockStub( mockStub &{} )
4 Entering CreateLoanApplication
5 PASS




测试通过。这是测试的绿色阶段,因为 CreateLoanApplication                方法会始终返回一个错误。现在编写另一个测试,该测试将揭示此缺陷并导致代码重构。
清单 10. 一个揭示缺陷的新测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var loanApplicationID = "la1"
var loanApplication = `{"id":"` + loanApplicationID + `","propertyId":"prop1","landId":"land1","permitId":"permit1","buyerId":"vojha24","personalInfo":{"firstname":"Varun","lastname":"Ojha","dob":"dob","email":"varun@gmail.com","mobile":"99999999"},"financialInfo":{"monthlySalary":16000,"otherExpenditure":0,"monthlyRent":4150,"monthlyLoanPayment":4000},"status":"Submitted","requestedAmount":40000,"fairMarketValue":58000,"approvedAmount":40000,"reviewedBy":"bond","lastModifiedDate":"21/09/2016 2:30pm"}`
  
  func TestCreateLoanApplicationValidation2(t *testing.T) {
    fmt.Println("Entering TestCreateLoanApplicationValidation2")
    attributes := make(map[string][]byte)
    stub := shim.NewCustomMockStub("mockStub", new(SampleChaincode), attributes)
    if stub == nil {
        t.Fatalf("MockStub creation failed")
    }

    stub.MockTransactionStart("t123")
    _, err := CreateLoanApplication(stub, []string{loanApplicationID, loanApplication})
    if err != nil {
        t.Fatalf("Expected CreateLoanApplication to succeed")
    }
    stub.MockTransactionEnd("t123")

}




第 1 和第 2 行将为贷款申请创建测试数据,这些数据被用作 CreateLoanApplication 方法的参数。
现在运行该测试。跟预期一样,测试将失败。
1 Entering TestCreateLoanApplicationValidation2
2 2017/02/22 23:09:01 MockStub( mockStub &{} )
3 Entering CreateLoanApplication
4 --- FAIL: TestCreateLoanApplicationValidation2 (0.00s)
5         sample_chaincode_test.go:55 Expected CreateLoanApplication to succeed
6 FAIL
7 exit status 1




现在,重构 sample_chaincode.js 中的 CreateLoanApplication 代码,以便通过此测试。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0