LoginSignup
13
13

More than 5 years have passed since last update.

Golang 初めての Unit テスト #golang

Last updated at Posted at 2017-10-09

以前の記事(Golang と Line Notify を利用して API の証明書期限切れチェック)を作りましたが今回は単体テストを追加します。

Golang の単体テストとは

ざっくり調べた感じだと、以下の感じで作ってみたら良さそう

  • テスト対象のコードと同じ階層に置く(標準パッケージが同じ構造になっていた)
  • testing パッケージを利用する
  • テスト用の関数のプレフィックスに「Test」をつける
  • Assert が用意されていないため、自分で条件を記載する
    (テストケースを失敗させたいときは「testing.T.Error」や「testing.T.Fatal」を利用する)
    • testing.T.Error:以降の処理を継続して実行される
    • testing.T.Fatal:以降の処理が実行されない

テストコードを記載

テスト対象のコード

apichecker.go
package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "strings"
    "time"
)

func main() {
    var endpoint = flag.String("endpoint", "", "check target Endpoint URL")
    var lineToken = flag.String("token", "", "LINE notify token")
    flag.Parse()

    var apiResult = getAPI(*endpoint)
    var result = postLINE(*lineToken, apiResult)

    fmt.Printf("LINE Post result [%t]\n", result)
}

func getAPI(endpoint string) string {
    if endpoint == "" {
        log.Println("not endpoint")
        return "not endpoint"
    }

    var result = ""
    resp, err := http.Get(endpoint)
    if err != nil {
        result = fmt.Sprintf("NG\n%s", err)
    } else {
        defer resp.Body.Close()
        expire := "-"
        if len(resp.TLS.PeerCertificates) > 0 {
            expireUTCTime := resp.TLS.PeerCertificates[0].NotAfter
            expireJSTTime := expireUTCTime.In(time.FixedZone("Asia/Tokyo", 9*60*60))
            expire = expireJSTTime.Format("06/01/02 15:04")
        }
        result = fmt.Sprintf("OK (expire=%s)\n%s", expire, endpoint)
    }

    return result
}

func postLINE(token string, message string) bool {
    if token == "" {
        log.Println("not token")
        return false
    } else if message == "" {
        log.Println("not text")
        return false
    }

    data := url.Values{"message": {message}}
    r, _ := http.NewRequest("POST", "https://notify-api.line.me/api/notify", strings.NewReader(data.Encode()))
    r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    r.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
    resp, err := http.DefaultClient.Do(r)
    if err != nil {
        log.Println(err)
        return false
    }
    defer resp.Body.Close()
    _, err = ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Println(err)
        return false
    }

    return true
}

getAPI のテストコードを書いてみる

同一パッケージなので、private な関数もテストできて便利
以下のパターンのテストケースを用意

  • パラメータエラー
  • 正常に実行完了
  • 証明書エラー
apichecker_test.go
package main

import (
    "regexp"
    "testing"
)

func TestGetAPI_パラメーターエラー(t *testing.T) {
    if getAPI("") != "not endpoint" {
        t.Error("failed validation check")
    }
}

func TestGetAPI_正常(t *testing.T) {
    r := regexp.MustCompile("OK \\(expire=[0-9]{2}/[0-9]{2}/[0-9]{2} [0-9]{2}:[0-9]{2}\\)\nhttps://www.yahoo.co.jp")
    if !r.MatchString(getAPI("https://www.yahoo.co.jp")) {
        t.Error("function format error")
    }
}

func TestGetAPI_証明書エラー(t *testing.T) {
    r := regexp.MustCompile("NG\n.+")
    if !r.MatchString(getAPI("https://www.yahoo.jp")) {
        t.Error("function format error")
    }
}

テストを実行

$ go test .
ok      github.com/ynozue/apichecker    0.684s

CI にも適用する

設定ファイルにテストの実行を追加

travis.yaml
language: go

install:
 - go get -u golang.org/x/tools/cmd/goimports
 - go get -u github.com/golang/lint/golint

script:
 - go vet ./...
 - diff <(goimports -d .) <(printf "")
 - diff <(golint ./...) <(printf "")
 - go test .

修正した内容を Git へ Push

Kobito.uPref4.png

$ go vet ./...


The command "go vet ./..." exited with 0.
$ diff <(goimports -d .) <(printf "")


The command "diff <(goimports -d .) <(printf "")" exited with 0.
$ diff <(golint ./...) <(printf "")


The command "diff <(golint ./...) <(printf "")" exited with 0.
$ go test .
ok      github.com/ynozue/apichecker    2.600s


The command "go test ." exited with 0.

Appendix

13
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
13