Unit testing 测试在Golang中的处理程序中调用该方法

Unit testing 测试在Golang中的处理程序中调用该方法,unit-testing,go,Unit Testing,Go,我正在Golang中实现一个API。我有一个端点,在这里我使用其他包的参数调用一个方法。现在我需要检查,该方法已在请求中调用 下面是一个类似的小场景,我在做什么,我在期待什么 我的经纪人 测试处理器 在TestMyHandler中,我想检查是否调用了notifier.Notify 调查结果 我试图理解,但我不知道如何使用它们:( 我是Golang的新手,真的很兴奋能这么做。 请让我知道,如果我错过了什么,或者你可能需要更多的信息,更了解 要测试该通知程序,请调用Notify 不,你没有。你感兴趣

我正在Golang中实现一个API。我有一个端点,在这里我使用其他包的参数调用一个方法。现在我需要检查,该方法已在请求中调用

下面是一个类似的小场景,我在做什么,我在期待什么

我的经纪人 测试处理器 在TestMyHandler中,我想检查是否调用了
notifier.Notify

调查结果 我试图理解,但我不知道如何使用它们:(

我是Golang的新手,真的很兴奋能这么做。 请让我知道,如果我错过了什么,或者你可能需要更多的信息,更了解

要测试该通知程序,请调用Notify

不,你没有。你感兴趣的是处理程序做它应该做的事情,这似乎包括两件事:

  • 返回正确的响应(易于使用net/http/httptest.ResponseRecorder进行测试),然后

  • 有一些明显的副作用,这里发布一些通知

  • 测试2。您测试的是发出了通知,而不是调用了某个函数。 应该测试notify.notify产生的任何结果(例如数据库条目、文件、一些HTTP调用)。正式来说,这不再是单元测试,但对副作用的测试从来都不是严格的单元测试


    您可以做什么:将处理程序逻辑包装到某个对象中,并观察该对象的状态。丑陋。不要。

    这是使用依赖项注入和接口的好机会

    也就是说,我们需要提取
    通知程序的概念

    (警告:代码未直接测试)

    类型通知程序接口{
    通知(int,string)()错误
    }
    
    现在,为了避免与
    通知程序
    库混淆,请使用本地别名

    导入“github.com/myrepo/notifier”mynotifier
    
    然后,因为您使用的库将其作为函数导出,而不是在结构中导出,所以我们需要创建一个实现接口的结构

    键入myNotifier结构{}
    func(mn*myNotifier)Notify(n int,消息字符串)错误{
    返回mynotifier.Notify(n,消息)
    }
    
    然后修改函数:

    func MyHandler(writer http.ResponseWriter,request*http.request,notifier-notifier){
    // ...
    // ...
    通知者通知(4,“sdfsdf”)
    // ...
    // ...
    }
    
    然后在测试中,您现在可以自由发送间谍通知程序

    type spyNotifier struct {
      called boolean
    }
    
    func (n *spyNotifier) Notify(n int, msg string) error {
      n.called = true
      return
    }
    

    可能重复:@icza这似乎不同。我可能错了,但由于我对Golang不太习惯,这就是为什么我仍然无法测试helper方法的原因。:(,(如果您以链接答案中描述的方式模拟函数,您可以在模拟版本中执行任何操作,例如,您可以增加计数器以查看它被调用的次数。我完全理解您的观点。但我陷入了一种有点奇怪的情况,
    通知程序。notify
    不进行任何
    数据库
    输入或
    http
    校准l、 这是一种
    日志记录机制。所以我无法控制它。我说得清楚了吗?@Vinay,那么你不能测试它。如果它没有任何可观察的效果,你可能会说它甚至不会发生。如果你的日志记录系统设计为不可观察,那么你就不能观察它,这意味着你不能测试它。有些事情很简单无法测试y。如何将此处理程序添加到路由器,我遇到的错误如下-无法将MyHandler用作类型http.HandlerFunc
    
    func TestMyHandler(t *testing.T) {
        // Here I want to 
        req, _ := http.NewRequest("GET", "/myendpoint", nil)
        // ... Want to test that notifier.Notify is called
        // ...
    }
    
    type spyNotifier struct {
      called boolean
    }
    
    func (n *spyNotifier) Notify(n int, msg string) error {
      n.called = true
      return
    }