ãã¼ã ã®å ±ç¨èª(?)ãGoã«ãªã£ãã¨ããã®ããã£ã¦Goã®ãã¹ãã«ã¤ãã¦å ¥éãå§ããããã¹ãã³ã¼ãèªä½ã¯linux-test-project/ltpãç¬èªã§forkãããã®ãã¡ã³ããã³ã¹ãã¦ãããã¨Cã§ã¯ãããåºç¤ãããã¯åå¾ãã¦ãããªã¨ããæãã§ãããå ¥éãã¦ããä¸ã§Mockã«ã¤ãã¦å¦ã¶æ©ä¼ããã£ã¦ããã¾ã§ãã¾ã触ããæ©ä¼ããªããã®ã ã£ãã®ã§ç解ã«è¦ããã ãå°ãããã£ãã®ã§æ¸ãã¦ã¿ãã
ããããMockã«æ £ãã¦ãªãã®ã¯ãªãã ããã¨èããã
å²ã¨ãã®è¨äºã«ãããããªç°å¢ã«ãããããªã®ããªã¨æã£ãããããMock使ãããããªãé¢æ°ã«åãåºãã¦ãã¹ããããããããåä½ãã¹ãã§éããªããã¹ã¯integrationã¨ãã«èªåãã¹ããå®è£ ãã¦ããã¦Mockä¸è¦ã«ãã¦ãã¹ãããããããªæãã§ãã¨ãªããå¾ã¦ãã(?)ããã¨ã¯Mockã使ã£ã¦ãã¹ãã§ã¯ã¨ããã³ã¹ã¨ãã¦ã¯è¶³ããªãã¦æ¬¡å·¥ç¨ã«åããªããªã©ã®ç¹æ®ãªçç±ããã£ã¦å人ã®éçºã®ããããçã«ä½¿ã£ã¦ã人ã¯ããããã ãã©ãã¾ãç©æ¥µçã«æ¸ãã¦ãåºè·å¤å®ã¨ããå£ãè¶ããææã«ã¯ãªããªãã®ã§ä½¿ãããªãã¿ãããªã®ããã£ãã®ããªã¨ãæã£ã¦ããã(ããã¯ç¹æ®ãããä¾ãããããªã...)
å¤é¨APIã£ã½ããã®ãæ¸ã
ãã¹ããã«ãããã°ãªãã§ãããã¦ä¾ãã°httpã¢ã¯ã»ã¹ãããã100ã¾ã§ã®æ°åã®ãã¡ã©ã³ãã ã§è¿ããã®ãç¨æãã¦ãã
package main import ( "fmt" "math/rand" "net/http" "strconv" "time" ) func handler(w http.ResponseWriter, r *http.Request) { rand.Seed(time.Now().UnixNano()) fmt.Fprintf(w, strconv.Itoa(rand.Intn(100))) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
ãã¹ã対象ã®ã³ã¼ããæ¸ã
ä¸è¨ã®APIã使ã£ãã³ã¼ããæ¸ãã¨ãããªæãããã¹ã対象ã¯Runã«ãªããRunã®æ»ãã®æååã¯APIã®çµæ次第ã§å¤ãã£ã¦ãã¾ãã¨ããå®è£ ã«ãªã£ã¦ããããããåä½ãã¹ãããã¨ãªãã¨åãããæ°å¤ã許容ãããã¹ããæ¸ããDoHttpRequestã§åºå®å¤ãè¿ããããªãªãã·ã§ã³ãå®è£ ãããã«ãªã£ã¦ãã¾ã(ããã¾ã§ãªãå¤åãããã¦ã)ãããããæã«ä½¿ããã®ãã¢ãã¯ã使ã£ããã¹ãã«ãªãã
package main import ( "fmt" "io/ioutil" "net/http" ) func DoHttpRequest(url string) string { resp, _ := http.Get(url) defer resp.Body.Close() byteArray, _ := ioutil.ReadAll(resp.Body) return string(byteArray) } func Run(s string) string { return s + DoHttpRequest("http://localhost:8080") // å¼æ°ã®æååã¨ä¹±æ°ãé£çµãã¦è¿ã } func main() { fmt.Println(Run("test: ")) }
mockã使ãã«ã¯
åä½ãåããã対象ãinterfaceã使ã£ã¦æ½è±¡åãã¦ãã¹ãã³ã¼ãã§ã¯å¯¾è±¡ã®interfaceã«ãã¹ãç¨ã®å®è£ (Mock)ãDIããã¨ããæãã«ãªããä»ååããã対象ã¯DoHttpRequestãªã®ã§ããã使ã£ã¦ããã¨ãããªæããinterfaceãå®ç¾©ããã
package main import ( "fmt" "io/ioutil" "net/http" ) type APIer interface { DoHttpRequest(url string) string } type API struct {} func (a API) DoHttpRequest(url string) string { resp, _ := http.Get(url) defer resp.Body.Close() byteArray, _ := ioutil.ReadAll(resp.Body) return string(byteArray) } func Run(s string, a APIer) string { return s + a.DoHttpRequest("http://localhost:8080") } func main() { a := &API{} fmt.Println(Run("test: ", a)) }
ãã¹ãã³ã¼ãã¯ãããªæããAPIMockãå®ç¾©ãã¦interfaceãå®è£ ãã¦ãããã¨ã§mockã使ã£ã¦Runããã¹ããããã¨ãã§ããããã«ãªãã
package main import ( "testing" ) type APIMock struct {} func (a APIMock) DoHttpRequest(url string) string { return "" } func TestRand(t *testing.T) { ai := &APIMock{} tests := []struct { a string b string }{ { a: "test: 1", b: "test: 1", }, } for _, tt := range tests { res := Run(tt.a, ai) if tt.b != res { t.Errorf("got: %s, want: %s", res, tt.b) } } }
interfaceã®åãè¾¼ã¿
以ä¸ã®ããã«interfaceãå®ç¾©ããã¦ããã¨ãããããããã¹ããããã®ã¯DoHttpRequestã ãã®å ´åã«ãã¹ãã³ã¼ãã«å ¨ã¦å®è£ ãã¦ããã®ã¯å¤§å¤ã«ãªã£ã¦ãã¾ããããããæã«ä½¿ããã®ãInterfaceã®åãè¾¼ã¿ã(ããã¯TDDã¨ãã§ä½¿ãããããã®ã ããã)ãåãè¾¼ã¿èªä½ã¯effective_goã¨ãã«ãè¼ã£ã¦ããã
type APIer interface { DoHttpRequest(url string) string DoHttpRequest2(url string) string DoHttpRequest3(url string) string DoHttpRequest4(url string) string DoHttpRequest5(url string) string }
type APIMock struct { APIer }
gomock
ä»è¨èªã«ããããããªãã¼ã«ãªã®ã§ããã ãããªã¨æã£ã¦ã¿ã¦ãããã£ããæ¯åä½ãã®ãé¢åèããã§ä¾¿å©ããã