Как сравнить / сопоставить замыкания в макетах? - PullRequest
0 голосов
/ 29 февраля 2020

TL; DR: смоделированный метод принимает закрытие. Интересно, как создать собственный сопоставитель (https://godoc.org/github.com/golang/mock/gomock#Matcher): само замыкание, в свою очередь, работает с частной структурой, то есть я даже не могу вызвать замыкание в своем тесте, чтобы проверить его на соответствие ожиданиям.


Я работаю над небольшим приложением, использующим Slack API, с помощью nlopes / slack (https://github.com/nlopes/slack).

Для тестирования я издеваюсь над nlopes / расслабиться с гомоком. Для этого я создал интерфейс

type slackAPI interface {
    OpenConversation(*slack.OpenConversationParameters) (*slack.Channel, bool, bool, error)
    PostMessage(channelID string, options ...slack.MsgOption) (string, string, error)
    GetUserByEmail(email string) (*slack.User, error)
}

У меня нет проблем с тестированием OpenConversation или GetUserByEmail, например,

slackAPIClient.
    EXPECT().
    GetUserByEmail("some@email.com").
    Return(slackUserJohndoe, nil).
    Times(1)

Ситуация усложняется, когда дело доходит до PostMessage. В основном коде вызов выглядит так:

_, _, err := slackAPIClient.PostMessage(channel.ID, slack.MsgOptionText(message, false))

И slack.MsgOptionText (из nlopes / slack) фактически возвращает замыкание:

func MsgOptionText(text string, escape bool) MsgOption {
    return func(config *sendConfig) error {
        if escape {
            text = slackutilsx.EscapeMessage(text)
        }
        config.values.Add("text", text)
        return nil
    }
}

Поскольку метод принимает закрытие, мне нужно создать Кастомный гомок-матчер (https://godoc.org/github.com/golang/mock/gomock#Matcher). Само пользовательское сопоставление не является проблемой, оно будет выглядеть примерно так:

type higherOrderFunctionEqMatcher struct {
    x interface{}
}

func (e hofEqMatcher) Matches(x interface{}) bool {
    //return m.x == x
    return true
}

func (e hofEqMatcher) String(x interface{}) string {
    return fmt.Sprintf("is equal %v", e.x)
}

Однако, поскольку MsgOptionText использует закрытую структуру nlopes / slack sendConfig, мне интересно, как я могу работать с этим в рамках моего теста, чтобы проверить равенство ожиданий.

Как мне решить эту проблему?

1 Ответ

1 голос
/ 01 марта 2020

Учитывая, что

  1. в Golang вы не можете сравнивать функции
  2. , в этом конкретном случае я не могу выполнить косвенный тест, вызвав само замыкание (так как оно используя в качестве аргумента частную стороннюю библиотеку lib)

решение, которое я нашел, состоит в том, чтобы смоделировать slack.MsgOptionText (message, false), который, в свою очередь, возвращает закрытие для PostMessage (строка channelID, параметры. ..slack.MsgOption):

type slackMsgCreator interface {
    MsgOptionText(string, bool) slack.MsgOption
}

type slackMsgCreatorInst struct{}

func (s slackMsgCreatorInst) MsgOptionText(text string, escape bool) slack.MsgOption {
    return slack.MsgOptionText(text, escape)
}

...

slackMsgCreator.
    EXPECT().
    MsgOptionText("Dear John Doe, message goes here", false).
    Return(slack.MsgOptionText("Dear John Doe, message goes here", false)).
    Times(1)

И, что касается PostMessage - как было рекомендовано в комментариях, единственное, что я мог проверить, - это закрытие не ноль:

slackAPIClient.
    EXPECT().
    PostMessage("ABCDE", Not(Nil())).
    AnyTimes()
...