对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(6)
- UID
- 1066743
|
对使用 Go 为 Hyperledger Fabric v0.6 编写的区块链链代码进行单元测试(6)
现在让我们进入测试的绿色阶段,编写通过此测试所需的最少量代码。使用此代码段更新 sample_chaincode.go 中的 Invoke 方法:
清单 19. 为了通过测试而需要向 sample_chaincode.go 中的 Invoke 方法添加的最少量代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
fmt.Println("Entering Invoke")
ubytes, _ := stub.ReadCertAttribute("username")
rbytes, _ := stub.ReadCertAttribute("role")
username := string(ubytes)
role := string(rbytes)
if role != "Bank_Admin" {
return nil, errors.New("caller with " + username + " and role " + role + " does not have access to invoke CreateLoanApplication")
}
return nil, errors.New("Invalid function name")
}
|
再次运行 TestInvokeFunctionValidation 测试。测试将会通过,因为 Invoke 方法会跟预期一样返回错误。但跟之前讨论的一样,您需要在下一个测试后重构此代码。
下一个测试将会传入正确的函数名 CreateLoanApplication 并要求调用该函数。此代码段展示了 TestInvokeFunctionValidation2 测试。
清单 20. TestInvokeFunctionValidation2 测试的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| func TestInvokeFunctionValidation2(t *testing.T) {
fmt.Println("Entering TestInvokeFunctionValidation2")
attributes := make(map[string][]byte)
attributes["username"] = []byte("vojha24")
attributes["role"] = []byte("Bank_Admin")
stub := shim.NewCustomMockStub("mockStub", new(SampleChaincode), attributes)
if stub == nil {
t.Fatalf("MockStub creation failed")
}
_, err := stub.MockInvoke("t123", "CreateLoanApplication", []string{})
if err != nil {
t.Fatalf("Expected CreateLoanApplication function to be invoked")
}
}
|
运行 TestInvokeFunctionValidation2 测试。跟预期一样,测试将会失败。
1 Entering TestInvokeFunctionValidation2
2 2017/03/06 20:50:12 MockStub( mockStub &{} )
3 Entering Invoke
4 --- FAIL: TestInvokeFunctionValidation2 (0.00s)
5 sample_chaincode_test.go:133 Expected CreateLoanApplication function to be
invoked
6 FAIL
|
现在重构 sample_chaincode.go 中的 Invoke 方法,以便处理函数调用委托。
清单 21. 重构 sample_chaincode.go 中的 Invoke 方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| func (t *SampleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
fmt.Println("Entering Invoke")
ubytes, _ := stub.ReadCertAttribute("username")
rbytes, _ := stub.ReadCertAttribute("role")
username := string(ubytes)
role := string(rbytes)
if role != "Bank_Admin" {
return nil, errors.New("caller with " + username + " and role " + role + " does not have access to invoke CreateLoanApplication")
}
if function == "CreateLoanApplication" {
return CreateLoanApplication(stub, args)
}
return nil, errors.New("Invalid function name. Valid functions ['CreateLoanApplication']")
}
|
现在重构 TestInvokeFunctionValidation2 测试,以便验证是否实际调用了 CreateLoanApplication 方法。理想情况下,应该使用一个 spy 对象来完成此操作,标准模拟库中提供了该对象,但为了简便起见,此测试将检查 Invoke 方法返回的输出来确保实际调用了 CreateLoanApplication 方法。
清单 22. 重构 TestInvokeFunctionValidation2 测试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| func TestInvokeFunctionValidation2(t *testing.T) {
fmt.Println("Entering TestInvokeFunctionValidation2")
attributes := make(map[string][]byte)
attributes["username"] = []byte("vojha24")
attributes["role"] = []byte("Bank_Admin")
stub := shim.NewCustomMockStub("mockStub", new(SampleChaincode), attributes)
if stub == nil {
t.Fatalf("MockStub creation failed")
}
bytes, err := stub.MockInvoke("t123", "CreateLoanApplication", []string{loanApplicationID, loanApplication})
if err != nil {
t.Fatalf("Expected CreateLoanApplication function to be invoked")
}
//A spy could have been used here to ensure CreateLoanApplication method actually got invoked.
var la LoanApplication
err = json.Unmarshal(bytes, &la)
if err != nil {
t.Fatalf("Expected valid loan application JSON string to be returned from CreateLoanApplication method")
}
}
|
现在再次运行该测试套件。TestInvokeFunctionValidation2 测试将会通过。 |
|
|
|
|
|