Help us understand the problem. What is going on with this article?

os.Exit()はDefer functionの実行を待たない

More than 3 years have passed since last update.

testingパッケージを利用してテストを記述している場合、初期化や終了後の後処理を記述するにはTestMain関数を利用する。

package test

import (
  "log"
  "os"
  "testing"
)

func TestMain(m *testing.M) {
  setup()
  code := m.Run()
  teardown()
  os.Exit(code)
}

func setup() {
  // 何らかの初期化処理...
  log.Println("setupped here.")
}

func teardown() {
  // 何らかの終了処理...
  log.Println("cleaned up here.")
}

func TestCase(t *testing.T) {
  t.Errorf("the test always fails")
}

この時、いつもの癖でteadown()deferで呼ぶコードを書いてしまうとする。こんなかんじだ。

func TestMain(m *testing.M) {
  setup()
  defer teardown()
  code := m.Run()
  os.Exit(code)
}

しかし、この書き方では問題が起こる。

deferを使ってしまうとこうなる
2015/06/13 00:06:04 setupped here.
=== RUN TestCase
--- FAIL: TestCase (0.00s)
    test_test.go:29: the test always fails
FAIL
exit status 1   <--- teardown()が実行されていない!!
FAIL    github.com/harukasan/test/test  0.008s

os.Exit(code)は全てのdeferを破棄して終了する。そのため、deferが正常に実行されずに、後処理が行われないのである。

で、どうするかなんだけど、まず考えるのはdeferの中でos.Exit(code int)を呼ぶ方法である。うまいこと終了コードを渡さないといけないので、あまり綺麗じゃないけどポインタ渡しにした。

func TestMain(m *testing.M) {
  setup()
  var code int
  defer func(int *code) {
    teardown()
    os.Exit(*code)
  }(&code)

  code = m.Run()
}

他の方法としては、codeをグローバル変数にする方法がある。

var code = 0

func TestMain(m *testing.M) {
  setup()
  var code int
  defer func() {
    teardown()
    os.Exit(code)
  }()

  code = m.Run()
}

どっちもどっちっぽいし、そもそもdeferを使うのをやめた方が綺麗なんじゃないかと思う。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away