如何进行测试去常规?

时间:2013-09-23 09:08:20

标签: testing go

此问题的一个示例是用户创建资源并删除资源。我们将执行操作并递增(递减)计数器缓存。

在测试中,有时存在竞争条件,其中计数器高速缓存尚未由go例程更新。

编辑:很抱歉有混淆,澄清一下:计数器缓存不在内存中,它实际上是数据库中的一个字段。竞争条件不是内存中的变量,实际上goroutine写入数据库本身可能会很慢!

我目前在操作后使用1秒睡眠,以确保在测试计数器缓存之前已更新计数器缓存。有没有另一种方法来测试常规,没有任意1秒的睡眠等待go例程完成?

干杯

2 个答案:

答案 0 :(得分:3)

  

在测试中,有时存在竞争条件,其中计数器高速缓存尚未由go例程更新。我目前在操作后使用1秒睡眠,以确保在测试计数器缓存之前已更新计数器缓存。

哎呀,我不想这么说,但是你做错了。 Go具有一流的功能,使并发变得容易!如果你正确使用它们,就不可能有竞争条件。

事实上,有一个工具detect races for you。我敢打赌它抱怨你的程序。

一个简单的解决方案:

  • 让主例程创建一个用于跟踪计数器的goroutine。
  • goroutine只会执行一个select并获得一条消息来递增/递减或读取计数器。 (如果是阅读,它将在一个频道中传递以返回号码)
  • 创建/删除资源时,通过其频道向goroutine计数器发送相应的消息。
  • 当您想要阅读计数器时,发送要阅读的消息,然后阅读返回通道。

(另一种选择是使用锁。它的性能会更高一些,但编写起来要麻烦得多,并确保它是正确的。)

答案 1 :(得分:0)

一种解决方案是让您的计数器提供一个价值尽快更新的频道 变化。通常,通过传达结果进行同步。比如你的 Couter可能如下所示:

type Counter struct {
   value int
   ValueChange chan int
}

func (c *Counter) Change(n int) {
    c.value += n
    c.ValueChange <- c.value
}

每当调用Change时,新值将通过通道传递,无论是谁 等待值取消阻塞并继续执行,因此与之同步 计数器。使用此代码,您可以在ValueChange上收听此类更改:

v := <-c.ValueChange

同时调用c.Change不再是问题。

runnable example on play