My Favorite Life

Go there and write simply with golang. Such a person I want to be.

golang.tokyo #17に参加してきました!

golang.tokyo って?

プログラミング言語Goの導入企業メンバーが集まり、Goの普及を推進するコミュニティです。 トークイベント、ハンズオン、etcのイベントを開催していく予定です。

golang.tokyo #17 は、
テーマが「今あらためてテストの話」で、テストについての回でした!

f:id:abemotion:20180825001457j:plain

f:id:abemotion:20180825001542j:plain 会場は freee さん。
美味しい食事やお酒をたくさんご用意いただきました...!

各発表のポイントや気になった点について、まとめていきたいと思います。

タイムテーブル

時間 内容
19:00 ~ 開場・受付
19:30 ~ 19:40 オープニング
19:40 ~ 20:10 Tour of testing by budougumi0617
20:10 ~ 20:40 非公開な機能を使ったテスト by tenntenn
20:40 ~ 21:10 休憩
21:10 ~ 21:20 LT1 外部環境への依存をテストする by duck8823
21:20 ~ 21:30 LT2 Developer-friendly なテストを考える by izumin5210
21:30 ~ 21:40 LT3 止めたいのに止められないテストの話 by knsh14
21:40 ~ 21:50 終了・撤収

Tour of testing by budougumi0617

1つ目は、@budougumi0617 さんによる Tour of testing in 2018 の発表でした。

説明された内容や、文中のリンクは以下のブログに記載されています。 https://budougumi0617.github.io/2018/08/19/go-testing2018/

自己紹介

Today's contents

Today's goal

Introduction 01

Start test 02

  • Basic and Naming
    • ファイル名はxxx_test.go
    • go test のときだけビルド
  • Test data を用意する

  • Execute test

# カレントパッケージのテストを実行する
$ go test

# パスで指定されたパッケージのテストを実行する(相対パス指定が可能)
$ go test ./table

# サブパッケージを含めたパスで指定されたパッケージ以下のテストを全て実行する
$ go test ./...

# 特定のテストコードだけを実行する(テスト対象も含めて実行する)
$ go test sum_test.go sum.go

# カレントパッケージ配下にある"Minus"というサブテスト(後述)だけを実行するとき
$ go test ./... -v -run /Minus

# Race condition の検出
$ go test ./... -race
  • go vet を抑制する
    • $ go test -vet=off
    • Go 1.10からテストの実行前にgo vet が実行される
  • Test Cache

    • Go 1.10から go build/testの結果がキャッシュされる
    • キャッシュを削除する / go clean -testcache
    • キャッシュなしで実行 / go test -count=1
  • -parallel nオプションで最大並行実行数を制御する

    • T.Parallel()メソッドが呼ぶテストケースは並行実行
    • $GOMAXPROCS
    • parallel nオプションのnで同時実行数を制御
  • cpu listで$GOMAXPROCSを変更しながらテストする

  • playgroundでテストを実行できる
    • 実はそのまま動かせるようになったのは最近

How to write test

  • テストコードのパッケージ
    • ディレクトリに複数パッケージは通常許されない
    • 例外的に"xxx"と"xxx_test"は共存可能
  • TB.Error / TB.Errorf
    • テストの失敗が記録される
    • 後続処理は継続される
  • TB.Fatal / TB.Fatalf
    • 失敗が記録され、テストケースが即時終了する
    • その場で宣言済み
  • TB.Fail
    • TB.Error / TB.Errorf が内部的に呼んでいる
  • TB.FailNow
    • TB.Fatal / TB.Fatalf が内部的に呼んでいる
  • TB.SkipNow / TB.Skip
    • テストケースを無効化する
  • TB.Log / TB.Skip
    • -vオプション、あるいはFailしたときにログ出力
    • ベンチマーク時は常に出力
  • want / got
    • expected? NO!
    • actual? NO!
    • 変数名は短いほうがGo way

Get coverage

  • Goは標準機能でテストカバレッジを計測できる
  • Go1.10からは複数パッケージのカバレッジも簡単に取得できるようになった
    • go test -cover ./...
  • go toolでカバレッジの計測結果をHTMLに出力できる

Today's summary

  • go testコマンド / testing.T を改めて確認
    • Go 1.10までの仕様を復習
  • ベタープラクティスをまとめる
  • ひとつでも多く新しい発見をしてもらう

質疑応答

  • Q . 並行テストの使い方は?

    • 「あまり意識してないですが、単純に遅いので早くするため。 個人的にはやってないが、プロジェクトではやっています。」
  • Q . 並行のオーバーヘッドは?何行からやる?

    • 「意識して遅くなることはないと感じています。」

@budougumi0617 さんのスライドは、こちらも大変参考になりました!
※ クイズ形式みたいになっていて、解きながら読み進められます

初級者向けGoの落とし穴と解説 / Traps and Explanations in Go

非公開な機能を使ったテスト

2つ目は、@tenntenn さんによる 非公開な機能を使ったテスト の発表でした。

内容的には「こちらに、ちょっと情報を足したバージョンです」とのこと。
Go Fridayこぼれ話:非公開(unexported)な機能を使ったテスト #golang

TL;TD(too long; didn't read.)

  • テストはテスト対象と別のパッケージにしよう
  • 別パッケージだと非公開な機能にアクセスできない
  • export_test.go というファイルを使うと解決する

テストはテスト対象と別のパッケージにしよう

  • テストが外部のパッケージになる
  • テスト対象のパッケージのユーザーと同じ視点で書く必要がある
    • Exampleテストを使う手もある
    • 使いづらい部分を早期に発見できる
  • テストが内部のコードに依存しなくなる
    • 公開(exportedな)された機能にしかアクセスできない
    • 非公開な機能にはアクセスできない

別パッケージだと非公開な機能にアクセスできない

  • 内部で使用している複雑な機能をテストしたい
    • unexportedな関数で実装されている
    • いろんなところで呼ばれている
    • 関数単体でテストしたい
  • 本当に非公開にする必要があるのか?
    • そんな複雑な処理をunexportedにしておく必要があるのか?
    • internalパッケージにする?
      • internalパッケージのexportedな機能とする = テストできる
    • 別のパッケージに切り出す?

export_test.go というファイルを使うと解決する

// export_test.go
package mypkg // テスト対象と同じパッケージ
const ExportMaxValue = maxValue
// テストコード
func TestMypkg(t *testing.T) {
    if doSomething() > mypkg.ExportMaxValue { // ExportMaxValue が公開されているのでアクセスできる
        t.Error("Error")
    }
}
  • テストのときだけビルド対象にする
    • *_test.goはgo testのときだけビルドされる
  • _test.goをつけてテスト対象と同じパッケージにする
    • テストのときにしかビルドされないファイルになる
    • テスト対象パッケージのテスト用の機能になる

まとめ

  • テストは別パッケージにしましょう
  • 非公開な機能はexport_test.goが有効
    • テストにだけ一部を公開する
    • 公開する範囲がコントロールができる
    • メソッド式や型エイリアスを使いこなす

別のパッケージにすることで、
ユーザーの気持ちになってテストが書けるというのは面白いと思いました...!

@tenntenn さんには Gopher 道場でもお世話になっていますが、
スライドを流しながら、スライド外の細かい解説までして下さるので、
聞いていて本当に興味深いです...!

参考

メルペイがGopher道場をサポートする理由 #メルペイなう vol.16 #gopherdojo - mercan(メルカン)

最後に

LTいただいた方々の資料も、こちらにまとめておきます!

外部環境への依存をテストする

Tips for develoepr-friendly testing #golangtokyo - Speaker Deck

止めたいのに止められないテストの話