【GitHub Actions】【Go】Goのテストに入門するついでにプルリクのテストの自動化と自動通知をやってみた

# まえがき
お久しぶりです。<b>Fuse</b>です
今回はGithub Actionsなる物に手を出してみました。
様々な処理を自動化して、いろいろ便利になるんだと聞き、いても立ってもいられなくなり筆を執ってみました。
# ソースコード
https://github.com/Fuses-Garage/TestofTest
# 解説
## Go編
### まずはテスト対象の関数を書く
テストの自動化をやってみる前にまずテスト対象の関数を作らねば話になりません。
まずは今回テストする関数である`Add`関数の仕様を考えてみます。
> __intのスライス__ を入力されると、__値の合計__ を __int__ で返す。

その仕様をもとに出来上がった`Add`関数がこちらになります。
```calc.go
package TestofTest

func Add(x []int) int { //intスライスの合計を返す
	sum := 0              //合計を格納する変数
	for _, v := range x { //スライスの中身を1つずつ取り出す
		sum += v //加える
	}
	return sum //合計を返す
}
```
____
### テストを書く
____
#### テストケースを作る
考えた仕様をもとに、__テストケース__ をいくつか考えてみます。
| args | want |
|:-:|:-:|
| (8,4) | 12  |
|(2,3)  |5|
|(1,3,5)|9|
|(1,2,3,4)|10|

テストケースを考えたら、それをテストケース用の構造体のスライスに起こします
``` go:テスト用構造体の定義
type TestCase struct { //テストケース用構造体
	identifier string//名前
	args       []int//入力値
	want       int//想定した出力
}
```
``` go:完成した配列の定義
tc := []TestCase{
    {"test01", []int{8, 4}, 12},
    {"test02", []int{2, 3}, 5},
    {"test03", []int{1, 3, 5}, 9},
    {"test04", []int{1, 2, 3, 4}, 10}
}
```
___
#### サブテスト用関数の実装
テストケースを考えたら、今度は小さなテストである __サブテスト__ を実装していきます。
構造体`TestCase`にテストを実行する`Testing`関数を実装しましょう。
```go:Testing関数
func (c TestCase) Testing(t *testing.T) {//テストを行う関数
	out := Add(c.args)//関数の出力値を取得
	success := out == c.want//テストは成功か？
	if success {//成功なら
		fmt.Printf("Success want:%d out:%d\n", c.want, out)//ログを出す
	} else {//失敗したら
		t.Errorf("Failed want:%d out:%d\n", c.want, out)//失敗のログを出す
	}
}
```
goのテストにてテストの失敗を通知するときは`Error`関数か`Errorf`関数を使います。
`Errorf`関数は`Printf`のようなもので、文の中に値を埋め込むことができ、便利です。
___
#### メインテスト用の関数の実装
最後に、配列化したテストケースを1つずつ実行する関数を作れば完成です。

:::note warn
   この際、メインテストの関数名は必ずTestで始まり、
   その後の1文字目は大文字か数字かアンダースコアにしましょう。
   下の画像のように表示されていればOKです。
   ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/c761bf81-d8be-3dc1-17f0-38f37dfbe76e.png)

:::
```go:TestAdd関数
func TestAdd(t *testing.T) {
	tc := []TestCase{
		{"test01", []int{8, 4}, 12},
		{"test02", []int{2, 3}, 5},
		{"test03", []int{1, 3, 5}, 9},
		{"test04", []int{1, 2, 3, 4}, 10},
	}
	for _, v := range tc {
		t.Run(v.identifier, v.Testing)
	}
}
```
ターミナルに`go test`と入力すると…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/6b150f39-83dc-7c3c-fa36-1b3d68ed8c54.png)

無事テストが完了し、このように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/fcd9d804-7ca2-bc80-9bda-375c35699310.png)

ちなみに失敗したときの表示はこんな感じ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/d6659eea-6d9f-a205-6476-8002cba7ac1f.png)

最後に、`go work init .`とターミナルに入力し、workファイルを生成すれば完了です。

:::note warn
ここでworkファイルを生成しないと、GitHubでのビルドが失敗します。
:::
## GitHub編
ここからは、 __GitHub Actions__ を使って、プルリクエストとmasterへのプッシュを自動でテストして通知する仕組みを使っていきたいと思います。
____
### 前準備
GitHubで作業する前に、通知を受け取る側であるDiscordでの設定を行います。
サーバ設定の連携サービスから新しいWebHooksを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/8046a5ac-b020-6fa3-5199-9ba2b45b3a49.png)

:::note
アイコンは[CHARAT](https://charat.me/)にて作成しました
:::

:::note alert
このウェブフックURLは絶対に外部に漏らさないように気を付けてください。
悪意を持った人間がGitHubになりすましあなたのサーバーに投稿を行えてしまいます。
:::

Discordでの作業が終わったら、いよいよGitHubでの作業に移ります。
ウェブフックURLを隠ぺいするために、`Actions secrets and variables`にウェブフックURLを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/f6075975-051d-193f-e4d6-848ac369ab9a.png)


:::note warn
GitHub Actionsはpublicリポジトリでは無料ですが、
privateリポジトリでは使用時間に応じ料金がかかります。
:::
### ワークフローを作る
コードを自動でビルドしてテストするワークフローを作りましょう。
といってもビルドしてテストするワークフローはGitHubの公式が提供してくれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/16041b73-7cd8-0fd6-6478-816b633ad902.png)



これをちょっといじってWebHooksを使ってDiscordに通知する機能をくっ付けちゃいましょう。
```diff_yaml:
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: Go

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:

  build:
+   name: Test
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v3
      with:
        go-version: 1.19

    - name: Build
      run: go build -v ./...

    - name: Test
      run: go test -v ./...
+ notify:
+   runs-on: ubuntu-latest
+   needs: [build]
+   steps:
+   - name: notify to Discord
+     env:
+       SECRET_ENV: ${{ secrets.WEBHOOK_URL }}
+     run: curl $SECRET_ENV -i -H "Content-Type:application/json" -d '{"content":"プルリクエストが来てるみたいだね！"}'
```
WebHooksをつかってDiscordに投稿するには、JSONをURLにぶん投げます。
ワークフローを作ってプルリクを立てて、テストが通るとこんな感じの通知が無事Discordに届きました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/b89a5943-8a70-600e-8470-c78f56fe70c9.png)
それが終わったら、テストが通らないとマージできないように、`master`ブランチを保護するように設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/a0a84f94-35f9-f555-faf7-3834cca80040.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/7cfe93b4-8b0b-2857-6d75-73bc0516bd05.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/dae6d843-58f4-de1b-11b6-3d8405872435.png)

設定を終えてもう一度プルリクを立ててみると、ちゃんとテストが終わるまでプルリクがマージできないようになりました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2957248/fce0c287-9c01-5394-fee0-ab9aee90acba.png)
# あとがきと感想
最後の方は駆け足になってしまいましたが、これにて完成です！
軽い気持ちで触れてみましたが、自動テストで開発がもっと便利になりそうです！