2024-04-01
RustでMQTT Brokerを作成して、テストを書こうと思ったときに、GoのChannelで実現できる挙動は強力な味方となってくれます。 下記のようにChannelに受け取ったものを流すことができます。
channel := make(chan mqtt.Message)
var f mqtt.MessageHandler = func(client mqtt.Client, msg mqtt.Message) {
log.Printf("Sub data: %v\n", msg)
channel <- msg
}
if token := c.Subscribe(topic, qos, f); token.Wait() && token.Error() != nil {
log.Printf("Mqtt subscribe error %s", token.Error())
return nil, token.Error()
} else {
log.Println("Subscribe Success")
}
テストを書くとしたらタイムアウトも必須だと思うが、下記のようにselectを使って書くと良いと思います。
func TestPubSub(t *testing.T) {
publishPayload := "data"
messageChannel := subscribeWaitFirstPacket("topic_a", publishPayload)
Publish("topic_a")
select {
case msg := <- messageChannel:
assert(msg, expect)
case <- time.After(timeoutSecond):
t.Error("")
}
}
//動くコードではない
Goで書かれたモジュールは標準のtestingパッケージを利用すれば充分テストできると思っていましたが、他の言語で書かれたソフトウェアを統合/E2Eテストしようと思った際に、testing.Mを駆使すれば標準パッケージでやることも不可能ではないが、テストの前後にやることが多くなってきてtestingだけだと心もとない。そこで、stretchr/testifyのSuiteモジュールを使えば、前後で別ソフトウェアをbuild/runできるので便利そうです。
stretchr/testifyは他にも便利な機能がありそうなので使いこなしたいです。
type OriginalSuite struct {
suite.Suite
}
func (suite *OriginalSuite) SetupSuite() {
suite.T().Log("SetupSuite")
//ソフトウェアをbuildする
}
func (suite *OriginalSuite) TearDownSuite() {
suite.T().Log("TearDownSuite")
}
func (suite *OriginalSuite) SetupTest() {
suite.T().Log("SetupTest")
}
func (suite *OriginalSuite) TearDownTest() {
suite.T().Log("TeardownTest")
}
func (suite *OriginalSuite) BeforeTest(suiteName, testName string) {
suite.T().Log("BeforeTest")
//ソフトウェアを実行する
//testNameに応じて起動オプションを変更する
}
func (suite *OriginalSuite) AfterTest(suiteName, testName string) {
suite.T().Log("AfterTest")
}
func (suite *OriginalSuite) TestHoge() {
suite.T().Log("TestHoge")
}
func (suite *OriginalSuite) TestFuga() {
suite.T().Log("TestFuga")
}
// テスト実行
func TestSuite(t *testing.T) {
suite.Run(t, new(OriginalSuite))
}
この記事からtestifyを知りました Goテストモジュール Testifyをつかってみた - classmethod
自作のmqtt brokerのテストで下記のように使っています。 統合テスト例: integration_test/mqtt_test.go
XでShare