如何测试Golang频道/ go-routine

时间:2014-08-18 13:58:20

标签: testing concurrency go testify

我有一个包含一个字节数据的类型,并通过一个通道在那里发布新数据。其他代码可以使用Read函数读取最后写入的数据字节。

编辑:对于实际的可运行代码,请参阅https://github.com/ariejan/i6502/pull/3特别是文件acia6551.go和acia6551_test.go。测试结果可在此处查看:https://travis-ci.org/ariejan/i6502/jobs/32862705

我有以下内容:

// Emulates a serial interface chip of some kind.
type Unit struct {
  // Channel used for others to use, bytes written here will be placed in rxChar
  Rx chan byte

  // Internal store of the last byte written.
  rxChar byte // Internal storage
}

// Used internally to read data store in rxChar
func (u *Unit) Read() byte {
  return u.rxChar
}

// Create new Unit and go-routing to listen for Rx bytes
func NewUnit(rx chan byte) *Unit {
  unit := &Unit{Rx: rx}

  go func() {
    for {
      select {
      case data := <-unit.Rx:
        unit.rxData = data
        fmt.Printf("Posted 0x%02X\n", data)
      }
    }
  }()

  return unit
}

我的测试看起来像这样:

func TestUnitRx(t *testing.T) {
  rx := make(chan byte)
  u := NewUnit(rx)

  // Post a byte to the Rx channel
  // This prints "Posted 0x42", as you'd expect
  rx <- 0x42

  // Using testing
  // Should read last byte, 0x42 but fails.
  fmt.Println("Reading value...")
  assert.Equal(t, 0x42, u.Read()) 
}

起初我认为“阅读价值”发生在转发路由到写入数据之前。但“发布”消息始终在“阅读”之前打印。

所以,还有两个问题:

  • 这是处理传入字节流的最佳方式(9600波特; - ))
  • 如果这是正确的方法,我该如何正确测试它或我的代码有什么问题?

1 个答案:

答案 0 :(得分:1)

根据此处发布的文章进行猜测,看起来您在访问存储数据时无法保证操作顺序。您可以在goroutines之间共享的任何数据周围使用互斥锁。

这里更好的选择是使用长度为1的缓冲通道来写入,存储和读取字节。

使用-race测试您的程序以使用竞赛检测器始终是一个好主意。

由于这看起来非常像“流”,你很可能想要一些缓冲,并查看一些如何经常使用io.Readerio.Writer接口的例子。