Unit testing 如何在模拟中比较/匹配闭包?

Unit testing 如何在模拟中比较/匹配闭包?,unit-testing,go,mocking,closures,gomock,Unit Testing,Go,Mocking,Closures,Gomock,TL;DR:模拟方法接受闭包。我想知道如何创建自定义matcher():闭包本身又在使用私有结构——这意味着我甚至不能在测试中调用闭包来检查它是否符合预期 我在nlopes/Slack()的帮助下使用slackapi开发一个小应用程序 为了测试,我用gomock模拟nlopes/slack。为此,我创建了一个接口 type slackAPI interface { OpenConversation(*slack.OpenConversationParameters) (*slack.C

TL;DR:模拟方法接受闭包。我想知道如何创建自定义matcher():闭包本身又在使用私有结构——这意味着我甚至不能在测试中调用闭包来检查它是否符合预期


我在nlopes/Slack()的帮助下使用slackapi开发一个小应用程序

为了测试,我用gomock模拟nlopes/slack。为此,我创建了一个接口

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
    }
}
因为方法接受闭包,所以我需要创建自定义的gomock匹配器()。自定义匹配器本身不是问题,它看起来像

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,我想知道我如何在测试范围内使用它来检查与预期的一致性

我该如何解决这样的问题呢?

记住

  • 在Golang,你不能比较函数
  • 在这种情况下,我无法通过调用闭包本身进行间接测试(因为它使用私有第三方库的结构作为参数)
  • 我找到的解决方案是模拟slack.MsgOptionText(message,false),它反过来返回PostMessage的闭包(channelID字符串,options…slack.MsgOption):

    至于PostMessage,正如评论中所建议的,我唯一能检查的是闭包不是零:

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

    我不确定我是否完全理解您试图做的事情,但是您知道,在Go中,不可能比较函数,即,您无法检查传入的闭包是否与预期的闭包匹配,这只是不可能,在Go中不可能。我正在尝试为我的代码创建单元测试。为此,我正在模拟SlackAPI(它是nlopes/Slack实现),这样单元测试就不会有任何真正的调用。然后我为模拟函数设置期望值。当模拟函数接受正则变量、结构等时,这不是问题。您只需比较它们。这似乎是模拟函数接受闭包的问题(这是由nlopes/slack模块设计的,不是我的选择)。因为你不能比较围棋中的闭包。因此,我试图找出如何测试这样的函数:)我认为在这种情况下,最好的方法是检查传入的闭包不是
    nil
    ,仅此而已。停止模拟,编写简单的赝品。这更明智。我的应用程序要求JIRA获取一些信息,然后让相应的人放松。对于JIRA零件的测试,普通假货工作得很好。但对于松弛部分的测试——为了测试我的应用程序,我确实需要使用mock来验证行为(基本上,我的应用程序进行了哪些松弛调用)。对吗?
    slackMsgCreator.
        EXPECT().
        MsgOptionText("Dear John Doe, message goes here", false).
        Return(slack.MsgOptionText("Dear John Doe, message goes here", false)).
        Times(1)
    
    slackAPIClient.
        EXPECT().
        PostMessage("ABCDE", Not(Nil())).
        AnyTimes()