golangで開発ことはじめ〜インストール・実行・初歩テスト〜

# TL;DR

* goで開発を行うための準備とテストの手順を紹介します
* 具体的な内容は以下の通りです
    * goのインストール
    * プログラムの実行，バイナリの作成
    * テストの実行，カバレッジレポートの可視化

# golangのインストール

* 以下のような手順です．goのバージョンや，アーキテクチャ(amd64)は[go言語のダウンロードページ](https://golang.org/dl/)で確認してください．
    * [go言語のダウンロードページ](https://golang.org/dl/)から，OSに合わせたファイルをダウンロードします
    * ```/usr/local/go```に展開します(Windowsの場合は```C:\go```など，適当な場所でも良いです)
    * 環境変数を設定します
    * Windowsの場合はzipファイルをダウンロードして適当な場所に展開し，環境変数```Path```と```GOPATH```を設定すれば，コマンドプロンプトから実行できます

```bash
# OSXの場合
wget https://dl.google.com/go/go1.12.5.darwin-amd64.tar.gz
sudo tar xzvf go1.12.5.darwin-amd64.tar.gz -C /usr/local
# Linuxの場合
wget https://dl.google.com/go/go1.12.5.linux-amd64.tar.gz
sudo tar xzvf go1.12.5.linux-amd64.tar.gz -C /usr/local

# 両者共通
export GOPATH=~/.go
export PATH=/usr/local/go/bin:${GOPATH}:${PATH}

# goが実行できることを確認
which go
/usr/local/go/bin/go

go version
go version go1.12.5 darwin/amd64 # インストールした環境によって表示が異なる
```

# サンプルプログラムの作成と実行

## main.goの作成

* テスト用のシンプルなプログラムを作って実行してみます
    * 以下のような，main.goを作成します

```go
/*
Sample Program main.go
*/
package main

import(
	"fmt"
)

func HelloWorld() {
	fmt.Println("Hello go World!") // 文字列を出力する
}

func main(){
    HelloWorld() // メソッドHelloWorldをコールする
}
```

## 実行

* ```go run```コマンドで，プログラムを実行できます

```bash
go run main.go
Hello go World!
```

## ビルドとバイナリの実行

* ```go build```コマンドで，実行バイナリを作ることができます
    * 以下の例では，```main_bin```という名前の実行バイナリを作ります

```bash
go build -o main_bin main.go
./test
```

* 実行バイナリのファイルサイズが大きくなることが多いので，```upx```コマンドで実行ファイルを圧縮すると良いです
    * Mac OSXならhomebrewで，Linuxならyum，apt-getなど，パッケージ管理システムでインストールできます
    * 以下のように，実行バイナリ```main_bin```のファイルサイズが半分程度になります．

```bash
$ go build -o main_bin main.go
$ ls -l main_bin
2103928  5  9 12:40 main_bin*

$ upx main_bin
...<snip>...
Ultimate Packer for eXecutables
        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
   2103928 ->   1073168   51.01%   macho/amd64   test
...<snip>...
$ ls -l main_bin
1073168  5  9 12:40 main_bin*
```

# テストの作成

* goはプログラムのテストを作成できます
    * テストとは，メソッドをいろいろな条件で実行して，バグを発見したり，コードの修正の影響を確認したりする仕組みのことです
    * main.goのテスト用のプログラムとして，以下のようなmain_test.goを作成します
    * ```パッケージ名_test.go```のように，ファイル名の末尾に```_test```を付けることで，パッケージのテストも記述できます

```go
/*
Sample Program Unit Test for main.go
*/
package main

import(
	"testing"
)

// TestMain: 各テストを実行する前後に処理をしたい場合は，Runメソッドの前後に記述する
func TestMain(m *testing.M) {
	m.Run()
}

// TestHelloWorld: HelloWorldを実行する関数
func TestHelloWorld(t *testing.T){ // 個別のテスト用メソッド
	HelloWorld()
}
```

# テストの実行

* ```go test```コマンドで，テストを実行できます
    * ```-v```オプションで詳細なログ出力
    * ```-cover```でコードカバレッジ(テストの実行により通過したコード行の全体に対する割合)を得ることができます
        * このプログラムの場合は，main.goファイル内のHelloWorld関数しか実行していないので，全体の50%しか実行されません
        * HelloWorldメソッドは引数も返り値もないので，メソッドを実行してみる程度しかテストの意味がありませんが，引数を指定して複数回実行したり，返り値の期待値によって処理を変えたりすることができます

```bash
# ディレクトリ内のすべてをテスト対象にする場合は， ```go test -v -cover .```でよい
go test main_test.go main.go -v -cover
=== RUN   TestHelloWorld
Hello go World!
--- PASS: TestHelloWorld (0.00s)
PASS
coverage: 50.0% of statements
ok  	command-line-arguments	0.006s	coverage: 50.0% of statements
```

# カバレッジレポートの作成

* 以下の手順で，コードカバレッジを可視化することができます
    * テスト実行時に，```-coverprofile```を追加してカバレッジプロファイルを作成しておく
    * ```go tool cover```コマンドで作った```cover.out```をhtmlに変換する

```bash
# カバレッジプロファイル出力付きでテストを実行する
go test main_test.go main.go -v -cover -coverprofile=./cover.out
go tool cover -html=cover.out -o cover.html
```

* 生成されたcover.htmlを見ると，プログラムコードのうち，テストで通過した範囲を確認できます
![ss.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/309617/b7976791-53b4-4d77-d3e7-ed8309a785e0.jpeg)

# 参考

* [go言語のダウンロードページ](https://golang.org/dl/)