Golang макет функции с динамическими c вызовами функций - PullRequest
1 голос
/ 02 мая 2020

Я довольно новичок в Go и до сих пор узнаю о том, как все работает в Go, так что, с учетом сказанного, я изучал Go подход к тестированию и как насмешки будут работать в течение последних нескольких недель и большая часть информации, которую я нашел, основанная на конкретных функциях.

Например, все, что является функцией, передается либо как получатель, либо как параметр, однако проблема, с которой я сталкиваюсь, заключается в том, что моя функция использует регистр переключения для определения того, что эту функцию нужно вызывать, чтобы она не передавалась извне.

func (n *Notification) Notify(m Message) error {
    switch n.Service {
    case "slack":
        var s slack.Slack
        s.User = m.User
        s.Host = m.Host
        s.Provider = m.Provider
        s.SystemUser = m.SystemUser
        return s.SlackSend(n.Url)
    default:
        return errors.New(codes.CODE5)
    }
}

Выше кода показано, как выглядит функция, которую я хочу протестировать, и мне трудно разобраться, как я могу высмеивать SlackSend() function.

Я сталкивался с какой-то статьей, в которой говорится, что я должен написать функцию в тестовом файле, и когда я доволен тем, что делает функция, я должен написать реальный код. Мне это не кажется правильным, потому что для меня такое чувство, что у меня один и тот же код в двух местах, и тест использует только тестируемый код, и я могу изменить реальный код и нарушить его, не обнаружив тестами это.

Я в основном работаю над Python, и я привык использовать такие вещи, как Mock / MagicMock, которые могут перехватывать вызов функции и включать ее во время выполнения, поэтому заранее извиняюсь, если я не совсем получил Go s TDD подход.

Вот как будет выглядеть тестовый код, если кому-то интересно:

type MockSlack struct {
    *slack.Slack
}

func (s *MockSlack) SlackSend(url string) error {
    if url != "" {
        return nil
    } else {
        return errors.New("url empty")
    }
}

func TestNotify(t *testing.T) {
    m := Message{}
    n := Notification{
        Service: "slack",
        Url:     "https://dummy.io",
    }

    if err := n.Notify(m); err != nil {
        t.Errorf("SlackSend, expected: %s, got: %s", "nil", err.Error())
    }
}

Очевидно, структура MockSlack не действует, потому что она нигде не передается.

Если у кого-нибудь есть какие-либо советы о том, как я мог бы высмеять это или что я должен вместо этого сделать, я был бы очень признателен.

Заранее спасибо.

ОБНОВЛЕНИЕ: Фон

Это не веб-сервер / приложение своего рода. Это плагин аутентификации S SH, поэтому это будет приложение на стороне сервера. Что касается метода Notify, то он предназначен для картографирования. Таким образом, он может вызывать Slack, MS Teams, AWS SNS, которые предоставляют вызывающей стороне меньше условий для обработки, и как и где отправленное уведомление определяется методом Notify.

1 Ответ

0 голосов
/ 02 мая 2020

Если вы не можете изменить метод Notify, чтобы сделать его безопасным для тестирования. Один из вариантов - рассмотреть возможность использования monkeypatching . Вот пример , предоставленный для *net.Dialer:

func main() {
    var d *net.Dialer // Has to be a pointer to because `Dial` has a pointer receiver
    monkey.PatchInstanceMethod(reflect.TypeOf(d), "Dial", func(_ *net.Dialer, _, _ string) (net.Conn, error) {
        return nil, fmt.Errorf("no dialing allowed")
    })
    _, err := http.Get("http://google.com")
    fmt.Println(err) // Get http://google.com: no dialing allowed
}

ВНИМАНИЕ: его использование вне среды тестирования небезопасно.

...