如何编写单元测试来检查方法的线程安全性

3

我有一个像这样的对象:

type Store struct {
    mutex sync.RWMutex
    data  map[string]int
}

func (s * Store) Read(key string) int, error {
    // ...
    defer s.mutex.RUnlock()
    s.mutex.RLock()
    // ...
    return val, nil
}

func (s * Store) Write(key string, value int) error {
    // ...
    defer s.mutex.Unlock()
    s.mutex.Lock()
    // ...
    return nil
}

如何编写单元测试来检查ReadWrite方法是否线程安全?

我认为已经存在针对这种情况的模式,但我没有找到任何相关内容。

我了解了-race标志:

竞争条件检测器只能在运行代码时实际触发竞争条件时才能检测到它们,这意味着在真实工作负载下运行启用竞争检测的二进制文件非常重要。

我的问题是如何编写单元测试来模拟真实的工作负载。


1
Go文档中了解关于-race构建/测试标志的内容。 - Adrian
@Adrian 你好,我了解到-race标志: “只有在运行代码时触发竞争条件时,竞争检测器才能检测到竞争条件,这意味着在实际工作负载下运行启用竞争的二进制文件非常重要。” 我的问题是如何编写单元测试来模拟实际工作负载。 - Dmitriy.Sh.
1
通过编写测试来模拟真实工作负载...这并没有简单的答案。这取决于您的具体情况。您需要自己解决这个问题。 - Adrian
2
单元测试不适用于真实工作负载下运行。如果您正在测试真实工作负载,则根据定义,您不是在运行单元测试。对于您想要的测试类型,最好的选择是在生产样式负载下运行“-race”构建的二进制文件。但不要将其与单元测试混淆,因为它具有完全不同的目的。 - Jonathan Hall
1个回答

5

使用Race detector运行您的测试。简而言之,运行如下:

go test -race

如果要构建普通二进制文件,例如在演示服务器上运行,请使用以下命令:

go build -race

但是有更多的选择,最好仔细阅读一下它:)

如果你的目标是在真实负载下进行测试,你最好的选择是使用 go build -race 编译你的代码,然后在真实负载下运行它。这可能意味着在一个暂存服务器上。但不要将其与单元测试混淆!

单元测试是用于测试单元——通常是独立函数等小部分代码的测试。负载/竞争测试是一头完全不同的野兽,需要不同的工具和完全不同的方法。

Go 很容易使用竞争检测器来运行单元测试,并经常捕获竞争情况。但不应该期望它能够捕获所有竞争情况,因为单元测试执行的性质与生产执行完全不同。


同时不要忘记,竞态条件只是可能的并发错误之一。其他错误包括死锁、活锁和饥饿。这四种错误都很难仅通过测试来消除,尽管测试可以证明它们的概率低于某个阈值。更多信息请参见:https://www.bigbeeconsultants.uk/post/2008/four-horsemen/ - Rick-777

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接