【问题标题】:How to check how many times a function has been called in a test?如何检查一个函数在测试中被调用了多少次?
【发布时间】:2020-12-25 03:25:31
【问题描述】:

我正在使用调用函数的 API 开发 Web 服务器。此函数执行繁重的工作并缓存结果。我的设计方式是,如果没有缓存并且多个用户同时使用相同的参数调用此 API,则服务器只为第一个请求调用该函数一次,所有其他请求等待完成工作和从缓存返回响应。

我用这种方式为它写了一个测试:


func TestConcurentRequests(t *testing.T) {
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            // do the request
            wg.Done()
        }
    }
    wg.Wait()
}

我可以通过在该繁重函数中打印一个值来检查我的代码是否正常工作,并检查控制台以查看它是否只出现一次,但我正在寻找一种方法使测试失败,如果此函数已被调用更多次。像这样的:

if n := NumberOfCalls(MyHeavyFunction); n > 1 {
    t.Fatalf("Expected heavy function to run only once but called %d times", n)
}

【问题讨论】:

  • 通常情况下,您可能应该测试一个函数被调用了多少次。相反,您应该检查它是否产生了您期望的输出。理论上,应该可以重构代码,使函数被调用更多次,或者更少(可能为0次)。如果发生这种情况,并且代码仍然正常运行,则测试应该通过。换句话说:大多数检查函数执行次数的测试实际上是在测试错误的东西。

标签: go testing


【解决方案1】:

我建议将您的繁重功能分解为缓存部分和实际处理部分。这里的缓存部分将是并发客户端的外观。这里的待测系统其实就是缓存层,决定是转发请求、保持还是从缓存中返回。因此,为了测试您需要模拟执行处理的实际函数,并且模拟应该记录它服务了多少请求。

这是带有某些假设的演示:

package main

import "fmt"

func CreateCachedProcessor(processor Processing) func(string) string {
    //cache here
    return func(req string) string {
        //Assume you have some logic to call the actual processor based on your conditions
        return processor.ProcessRequest(req)
    }
}

type Processing interface {
    ProcessRequest(string) string
}

type HeavyProcessing struct{}

func (p *HeavyProcessing) ProcessRequest(request string) string {
    return "response"
}

type HeavyProcessingRecorder struct {
    Count int
}

func (p *HeavyProcessingRecorder) ProcessRequest(request string) string {
    p.Count += 1
    return "response recorded"
}

func main() {

    //normal
    hp := &HeavyProcessing{}
    c := CreateCachedProcessor(hp)
    fmt.Println(c("req1"))

    //Test with recorder
    hpr := &HeavyProcessingRecorder{}
    cr := CreateCachedProcessor(hpr)
    cr("req1")
    cr("req1")
    cr("req1")
    fmt.Println("No. of times Called ", hpr.Count)

}

【讨论】:

  • 嗨。感谢您的详细回复。与此同时,我找到了一个更简单的解决方案。我将我的繁重函数分配给一个变量,该变量将由我的 API 处理程序调用。然后在测试用例中,我将该变量的值更改为一个高阶函数,该函数将调用原始函数并在每次调用后增加一个外部范围整数值。最后,我应该检查那个 int 变量的值。
  • 对你有用的都可以。在我的情况下,这也是 hpr 变量。但我不想把 Count 变量放在那里,因为我认为这是被测系统,它是 CachedProcessor(生产功能)。记录器应该在被测系统之外。
猜你喜欢
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-15
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多