Go言語で画像生成のテストを書く #golang
この記事はGo3 Advent Calendar 2019の18日目の記事です。
この記事ではGo言語における画像生成のテスト方法を紹介します。
画像生成というのはロジックに手を入れていなくてもライブラリがアップデートされたタイミング等でバグりやすい箇所です。
テストを用いてデグレの確認を常に行いましょう。
サンプルアプリ
今回の説明のために文字を画像に文字を印字するCLIを書いてみました。
こんなコマンドで
$ print-on-image -d 'hello, world' -o example.jpg
このアプリを例に説明します。
テスト対象は run
という関数です。
引数に印字する文字列 drawValue
と印字した画像を保存するWriter w
を取ります。
func run(drawValue string, w io.Writer) error { if drawValue == "" { return errors.New("draw value is empty") } baseImg, err := getBaseImage() if err != nil { return err } fo, err := getFont() if err != nil { return err } drawImg := drawStringToImage(baseImg, fo, drawValue) return jpeg.Encode(w, drawImg, &jpeg.Options{Quality: 100}) }
テストコード
14行目でテスト対象の関数を呼んでいます。
その際に bytes.Buffer
を引数の io.Writer
の部分に入れていることがわかると思います。
これは後で画像のbyteスライスを取得するためです。
その後は
- テスト画像の生成
- 実際のテスト
の2ルートに分かれます。
テスト画像の生成
最初はテスト画像が無い状態ですのでテスト画像の生成を行います。
環境変数 IS_CREATE_DST_FILE
を true
に設定してテストを実行します。
$ IS_CREATE_DST_FILE=true go test
すると createDstFile
が実行され、テスト画像の生成が行われます。
createDstFile
は最後に t.Skip
を実行しています。
これはテスト画像生成の場合は createDstFile
が終わったら終了してほしいためです。
(テスト画像生成の場合は実際のテストの実行はしない。)
テスト画像が生成されたら目視確認をして問題ないかを確認します。
# Macの場合 $ open _testdata/dst.jpg
テスト画像の生成は初回1度で良いと思われるかもしれませんがコードは残しておくことをおすすめします。
以前Goのバージョンが上がったときに画像生成のロジックが変わっており、生成される画像も目視では変わっていないように見えるものの、byte配列は変わっていました。
また、画像の生成ロジックをちょっと変更したいという時にもテスト画像の生成を使って出力される画像を確認しながら開発を進めることができるので便利です。
以上のような場合にテスト画像をすぐ作れるようにしておくためにもコードは残しておくと良いです。
実際のテスト
テスト画像を作成したら実際のテストを実行します。
実際のテストは IS_CREATE_DST_FILE
に何も設定しないでgo testを実行します。
$ go test
22行目でテスト画像である _testdata/dst.jpg
ファイルを読み込み、26行目でbyteスライスを取得。
31行目で引数に入れた bytes.Buffer
から Bytes
でbyte配列を取得して bytes.Equal
を使用して比較します。
今回はそれほど大きくない画像ファイルなので ioutil.ReadAll
ですべてのbyte配列を読み込んでいますが、大きいファイルの場合は Read
から数バイトずつ読み込んで比較するという方法を取ったほうがメモリ使用量が少なくなるはずなのでよいと思います。
まとめ
画像生成のテストを紹介しました。
これにより画像生成ロジックにデグレがあった場合でもすぐに分かるので安心してライブラリのアップデートを行うことができます。
また、テスト画像の生成を気軽に行えるようになったことで画像生成の開発も楽になるのではないでしょうか。
ぜひ皆さんのアプリでも実践してみてください。