Go 重構筆記 1 - Extract Method
Posted

一開始先來一個簡單的。
Background
有一系列的測試開頭都有這段一樣的前置 code:
- Create gomock controller
- Create temp dir
- Assert mocks is invoked
- Remove temp dir
package test
import (
"io/ioutil"
"os"
"testing"
"github.com/golang/mock/gomock"
)
func TestFoo(t *testing.T) {
ctrl := gomock.NewController(t)
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp directory: %v", err)
}
defer func(ctrl *gomock.Controller, dir string) {
ctrl.Finish()
os.RemoveAll(dir)
}(ctrl, dir)
// do something
}
func TestBar(t *testing.T) {
ctrl := gomock.NewController(t)
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp directory: %v", err)
}
defer func(ctrl *gomock.Controller, dir string) {
ctrl.Finish()
os.RemoveAll(dir)
}(ctrl, dir)
// do something
}
每次要新增一個 test case 就要寫一大堆漏漏長,越寫心情越差,可讀性低,
也不 DRY,還很 WET,不好笑。
Solution
其實這邊就是在做 unit test 的 setup
和 teardown
的部分
- Create gomock controller
setup
- Create temp dir
setup
- Assert mocks is invoked
teardown
- Remove temp dir
teardown
我們把 setup 的部分抽成一個 func setup()
,但因為 teardown
和 setup
有依賴,不能抽成兩個 func,
改成在 setup()
先包成一個 callback 回傳,之後在由 test case 各自 defer teardown()
。
package test
import (
"io/ioutil"
"os"
"testing"
"github.com/golang/mock/gomock"
)
func setup(t *testing.T) (*gomock.Controller, string, func()) {
ctrl := gomock.NewController(t)
dir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatalf("could not create tmp directory: %v", err)
}
teardown := func() {
ctrl.Finish()
os.RemoveAll(dir)
}
return ctrl, dir, teardown
}
func TestFoo(t *testing.T) {
ctrl, dir, teardown := setup(t)
defer teardown()
// do something
}
func TestBar(t *testing.T) {
ctrl, dir, teardown := setup(t)
defer teardown()
// do something
}
喔喔喔是不是乾淨多了?也可以很清楚知道這段 code 是在做什麼。