在 golang 函数中测试无法访问的执行路径

test unreachable execution path within golang function

我正在编写单元测试以覆盖下面结构链代码中的所有执行路径。但我看不到到达 JSON.Marshall 失败路径的方法。

如何传递传递给 json.Unmarshal 但无法传递给 json.Marshal 的值?

func (c *MyContract) CreateAsset(ctx contractapi.TransactionContextInterface, values string) (bool, error) {
    
    doctype := "myAsset"
    txData := []byte(values)
    docData := new(DocData)
    docData.DataType = doctype

    // validate json input & map to struct
    err := json.Unmarshal(txData, &docData)
    if err != nil {
        return false, fmt.Errorf("failed docData unmarshalling: %s", err.Error())
    }

    docKey, _ := createKey(ctx, doctype, []string{docData.Key1, docData.Key2})

    exists, err := c.DocExists(ctx, docKey)
    if err != nil {
        return false, fmt.Errorf("could not read from world state %s", err)
    } else if exists {
        return false, fmt.Errorf("asset already exists")
    }

    txBytes, err := json.Marshal(docData)
    if err != nil {
        return false, fmt.Errorf("failed docData bytes marshalling: %s", err.Error())
    }

    return true, ctx.GetStub().PutState(docKey, txBytes)
}

这是我当前的测试:

func TestCreateAsset(t *testing.T) {
    var err error
    ctx, _ := setupStub()
    c := new(MyContract)


    _, err = c.CreateAsset(ctx, "{")
    assert.EqualError(t, err, "failed unmarshalling: unexpected end of JSON input", "testing malformed json")

    _, err = c.CreateAsset(ctx, "{\"key1\":\"mis\",\"key2\":\"sing\"}")
    assert.EqualError(t, err, "could not read from world state some failure")

    _, err = c.CreateAsset(ctx, "{\"key1\":\"001\",\"key2\":\"002\"}")
    assert.EqualError(t, err, "asset already exists")

}

当无法封送数据中的值时,json.Marshal 函数失败。引发失败的唯一方法是引入一个用于测试的字段,并在测试期间输入错误的值:

type DocData struct {
    …
    Test       interface{} `json:"test,omitempty"`
}

…

var induceFailure interface{}

…

docData.Test = induceFailure
txBytes, err := json.Marshal(docData)
if err != nil {
    return false, fmt.Errorf("failed docData bytes marshalling: %s", err.Error())
}

…

func TestMarshlFail(t *testing.T) {
    induceFailure = make(chan struct{})
    defer func() {
       induceFailure= nil
    }()
    …

获得该行代码的测试覆盖率可能不值得。

与手头的问题无关,这里是对您的代码的一些改进。

  • 包装错误而不是将错误转换为字符串:

    return nil, fmt.Errorf("failed docData unmarshalling: %w", err)
    
  • 因为docData是一个指针,所以解组时不需要取值的地址。

    err := json.Unmarshal(txData, docData)