проверьте недостижимый путь выполнения в функции golang

# #go #hyperledger-fabric #hyperledger-chaincode

Вопрос:

Я пишу модульные тесты, чтобы охватить все пути выполнения в приведенном ниже цепном коде структуры. Но я не вижу способа добраться до неудачного пути 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 amp; map to struct
    err := json.Unmarshal(txData, amp;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")

}
 

Комментарии:

1. json.Marshal произойдет ошибка только в том случае, если вы передадите маршалу недопустимое значение. Если DocData это действительно так, то он не потерпит неудачу.

2. Кроме того, подумайте о последствиях добавления дополнительных векторов ошибок в ваш код исключительно для проверки на наличие ошибок, которых не должно быть, чтобы получить лучший номер покрытия. Предположительно, все, что потребляет выходные данные этой функции, уже проверяет свой false, error путь.

3. @JimB Я полностью понимаю твою точку зрения. В этом отношении было бы безопасно исключить ошибку захвата json.Marshal , так как к тому времени она была бы протестирована, верно?

4. ИМХО, я бы оставил проверку на ошибку, даже если это очень маловероятно, так как следующий человек, который прочтет код, будет ожидать этого, и написать проверку на ошибку не сложнее, чем комментарий, объясняющий, почему ошибка обрабатывается по-другому. Если вы не хотите возвращать ошибку, то следующим правильным поступком будет паника.

Ответ №1:

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)