CircleCIでshUnit2のテストを実施する

先日、「shUnit2を使おう」という以下のLTをしてきました。
http://www.slideshare.net/cottondesu/shell-02-shunit2

shUnit2を使ってシェルのテストするまでLTをしましたが、
本当はこのLTには続きあります。
動作確認する時間、スライドを作成する時間がなかったので実現
できなかったのですが、GithubとCircleCIが連携し
CircleCIでshUnit2のシェルテストを行うことです。

#目的
Githubにpushし、CircleCIでshUnit2のテストを実施する

#環境
* Mac
* shUnit2
* Github
* CircleCI

#shUnit2のインストール

以下のURLを開く
https://code.google.com/archive/p/shunit2/

Downloadsからshunit2-2.1.6.tgzをダウンロードします。
ターミナルから以下のコマンドを実行しフォルダを作成、
ダウンロードしたtgzファイルを展開します。

```
$ mkdir ~/.shunit2
$ tar zxf shunit2-2.1.6.tgz -C ~/.shunit2
```

以下のように環境変数(bash)を設定します。

```
$ echo 'export SHUNIT2_HOME=$HOME/.shunit2/shunit2-2.1.6' >> ~/.bash_profile
$ . ~/.bash_profile
```

sampleのテストコードは.shUnit2のexamplesディレクトリに
格納されているのでそちらでテストコードの書き方を確認ください。

#bashスクリプトのプロジェクト作成
テスト対象のシェルスクリプトとテストコードが必要になります。
ここではテストコードの書き方は省きます。
私の場合、シェルスクリプトがGithubにおいてあるのでこちらを使います。

https://github.com/cottondesu/shell_create_kzrb_meetup

シェルスクリプトのテスト対象ファンクション部分

```bash:create_kzrb_meetup.sh
#モード選択
select_mode() {
  if [[ "$1" =~ ^[1-2] ]]; then
    return 0
  else
    return 1
  fi
}

#meetup番号入力  
input_meetupnum(){
  if [[ "$1" =~ ^[0-9]+$ ]]; then
    return 0
  else
    return 1
  fi  
}

#フォルダ存在チェック
is_filefolder(){
  if [ ! -e "$1" ]; then
    return 1
  else
    return 0
  fi  
}
```

テストコード

```bash:test/function_test.sh
#!/bin/bash

# shellcheck source=./../../shell_create_kzrb_meetup/create_kzrb_meetup.sh
. "$(dirname "${BASH_SOURCE:-$0}")/../../shell_create_kzrb_meetup/create_kzrb_meetup.sh"

testSelectMode1(){
	select_mode 1
	assertEquals 0 $?
}

testSelectMode2(){
	select_mode 2
	assertEquals 0 $?
}

testSelectModeNg(){
	select_mode 3
	assertEquals 1 $?
}

testInputMeetupNum1(){
	input_meetupnum 1
	assertEquals 0 $?
}

testInputMeetupNum40(){
	input_meetupnum 40
	assertEquals 0 $?
}

testInputMeetupNumNg(){
	input_meetupnum a
	assertEquals 1 $?
}

testIsFile(){
	is_filefolder "$0"
	assertEquals 0 $?
}

testIsFileNg(){
	is_filefolder "index.md"
	assertEquals 1 $?
}

testIsFolder(){
	is_filefolder ../test
	assertEquals 0 $?
}

testIsFolderNg(){
	is_filefolder test
	assertEquals 1 $?
}

# shellcheck source=$HOME/.shunit2/shunit2-2.1.6/src/shunit2
. "$SHUNIT2_HOME/src/shunit2"
```

因みに上記のfunction_test.shをshellcheckするとnoteが2件でます。
shellcheck -xで実行すると57行目の1件のみnoteで出ます。
$HOMEを実際のパスに置き換えるとnoteが消えます。

#Githubにpush
私の場合は既にGithubにシェルスクリプトが格納されているので
テストコードを追加してpushします。

```
$ git add test/function_test.sh
$ git commit -m "テストコードを追加"
$ git push origin master
```

#CircleCIの設定 
CircleCI
https://circleci.com/  
  
1. CircleCIにgithubのアカウントでログインする
2. 左側のメニューにある[ADD PROJECT]を選択する
3. pushしたリポジトリの「BuildProject」を選択する。

3.を行うとすぐさまbuildが実施されますが、
「NO TESTS」となります。testが実施されていませんからね。

testが実施されるようにcircle.ymlを作成する

```yml:circle.yml
machine:
  environment:
    SHUNIT2_HOME: ${HOME}/.shunit2/shunit2-2.1.6

dependencies:
  pre:
    - "[ ! -e ~/.shunit2 ] && wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/shunit2/shunit2-2.1.6.tgz && mkdir ~/.shunit2 && tar zxf shunit2-2.1.6.tgz -C ~/.shunit2 || echo 'ready'"
  cache_directories:
    - "~/.shunit2"

test:
  override:
    - bash test/function_test.sh
```

test:の所でpush時に実行されるテストコードを指定します。
私の場合は、test/function_test.sh となります。

作成したcircle.ymlをpushする

```
$ git add circle.yml
$ git commit -m "add circle yml"
$ git push origin master
```

pushすると、CircleCI上でshUnit2によるテストが実行されます。
ここで成功したよドヤって言いたかったんですが、私のテストコードが
悪かったせいでFAILEDになってしまいました。

ローカル環境でのテスト実施はtestフォルダに移動して
テストコードを実施していました。

```
$ sh function_test.sh
```

上の階層(shell_create_kzrb_meetup)に移動して
テストコードを実施すると、CircleCIで実施した時と同じ
FAILEDが再現できました。

```
$ sh test/function_test.sh
```

ファイル存在やフォルダ存在などパスを確認するテストコードを
作成するときは実行するカレントフォルダを意識する必要があります。
我が身を持って大変勉強になりました。

以下のようにテストコードを直します。

```bash:function_test.sh修正前
testIsFolder(){
	is_filefolder ../test
	assertEquals 0 $?
}

testIsFolderNg(){
	is_filefolder test
	assertEquals 1 $?
}
```

```bash:function_test.sh
testIsFolder(){
	is_filefolder test
	assertEquals 0 $?
}

testIsFolderNg(){
	is_filefolder exsample
	assertEquals 1 $?
}
```

として直してcommit、pushします。

```
$ git add test/function_test.sh
$ git commit -m "テストコードの修正"
$ git push origin master 
```

無事、単体テストが成功しました。
本当は成功例のみを載せたほうが良いのかもしませんが
失敗例含めて少しでも役に立てば有難いです。

#参考にした記事
[shUnit2とCircleCIでシェルスクリプトの単体テストをしてみた](http://takemikami.com/2016/04/26/shUnit2CircleCI.html "shUnit2とCircleCIでシェルスクリプトの単体テストをしてみた")