Как я могу использовать динамические ошибки, сохраняя сопоставимость для тестирования?

#go #testing #error-handling

# #Вперед #тестирование #обработка ошибок

Вопрос:

В go я часто использую

 func MyFunc(s someInterface) error {
    err := OtherFunc(s)
    return fmt.Errorf("something wrong: %s", err)
}
 

Таким образом, я теряю исходное значение ошибки, потому что я просто беру строку ошибки и превращаю ее в новую ошибку. Это то, что я имею в виду под динамическими ошибками.

Теперь рассмотрим тест для MyFunc() :

 func TestMyFunc(t *testing.T) {
    s := mockSomeInterface()
    testErr := MyFunc(s)
    if testErr != interfaceSpecificErrorValue {
        t.Errorf("fail")
    }
}
 

Для чего я буду использовать interfaceSpecificErrorValue (что конкретно относится к someInterface этому примеру)? Или как я мог бы сделать это проверяемым?

Я понимаю, что могу решить эту проблему, заранее определив все мои возможные ошибки и присвоив им постоянное значение. Меня интересует, есть ли другой способ добиться этого, потому что мне нравятся иерархические сообщения об ошибках, которые вы можете динамически создавать, используя fmt.Errorf("...: %s, err) . Должен быть хороший способ сохранить иерархию ошибок без потери исходного значения.

(Сравнение выходных Error() данных метода возможно, но не очень хорошо.)

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

1. Может быть godoc.org/github.com/pkg/errors

2. Ошибки не обязательно должны быть строками. Стандартная библиотека полна типов ошибок, которые переносят другие, лежащие в основе ошибки ( os. Например , ошибка пути). Пакет, предлагаемый zerkms, быстр и прост в использовании, но я настоятельно рекомендую создавать конкретные полезные типы, которые позволяют обрабатывать ошибки, а не только сообщать о них.

3. @Peter не могли бы вы привести пример для конкретного, полезного типа? Я посмотрел на ОС. Ошибка пути, у него есть поле «Ошибка ошибки», содержащее ошибку «восходящий поток». Это то, что вы предлагаете?

4. ДА. Но у него также есть метод тайм-аута. На самом деле, многие типы делают это, и существует также общий временный метод . Они помогают вызывающим абонентам решить, стоит ли что-то повторять.

5. Разрешить обработку ошибок, а не только сообщать о них, — это тот намек, который мне был нужен. Хотя пакет, предложенный zerkms, безусловно, хорош для чтения, я не чувствую, что хочу добавлять это в свои проекты. Надеюсь, кто-нибудь добавит ответ с небольшим примером кода для хорошего, конкретного типа ошибки с контекстом, может быть, я придумаю что-нибудь позже.

Ответ №1:

Мой предварительный ответ на это таков: в Go в настоящее время нет канонического способа получения вложенных ошибок с сопоставимыми значениями ошибок.

После повторного прочтения официальных документов и сообщений в блогах об обработке ошибок, немного исходного кода из стандартных библиотек и, наконец, это предложение: https://github.com/golang/proposal/blob/master/design/go2draft-error-values-overview.md Поэтому я решил, что сохраню свои типы ошибок простыми и статичными и буду ждать, пока Go 2 предложит лучший способ.