はじめに
最近, Vim pluginを開発するようになって, テストをCIでぶん回したくなったので, 試行錯誤の結果メモ.
やりたいこと
僕はあんまりテストに深い思い入れがある訳ではないのだけど, 下記を実現したい気持ちがあった.
- コーディング中はVimから単体テストを実行したい.
- CIでもテストを回したいため, CLIからの実行も欲しい. READMEに"build passing"のバッジ貼りたい.
- テストを実行するための依存プラグイン管理の仕組みが欲しい.
Vim plguinのCIについて適当にググってみたところ, vim-flavorでテストをCLIから実行する, という方法が見つかったのだが, これは上記の1. と3. と背反するため, 今回は採用見送り.
また, vim-flavorは依存プラグインのバージョン指定がsemverに従ってないと上手く動作しない様子だったため, これも採用見送りの理由の一つ.
結局, 上記を全部充足するようなVimプラグインは特に見つからなかったので, NeoBundle + vesting + シェルスクリプトの構成を採用することにした.
NeoBundleは普段から使っているplugin manager, という理由.
vestingについては, 特に深い思いがある訳ではないが, NeoBundleと作者が一緒であり, 上記の1.に対応していたため.
やってみた
基本的な考え方
先述の通り, Vimを立ち上げてからの実行はvestingで出来るので, 作り込む必要があるのはCLI部分のみ.
今回は以下のアプローチでやってみた.
- レポジトリにneobundle.vimをclone.
- テスト用の.vimrcを用意し, テストに必要なVimの設定情報は事前に記述しておく.
- プラグイン本体, NeoBundleの
runtimepath
設定はこのファイルに記述 - テスト実行時に必要となる依存pluginはこのファイル中に
:NeoBundle
コマンドで列挙し,:NeoBundleInstall
で取得する
- プラグイン本体, NeoBundleの
- vestingを実行するためのマクロを用意する.
- vestingはUniteで結果を出力するため, この結果をログに吐き出すようにしておく.
- Vimをsilent-modeで起動する.
vim -u vest/.vimrc -s vest/_runner
. - vestの結果ログに
[Fail]
,[Error]
が存在するかどうか, grepする. 該当無しであればテスト成功とみなす.
コード解説
さて, 実際にQuramy/vesting-ciにサンプルのレポジトリ作って, TravisCIで動かしてみた.
レポジトリのディレクトリ構成は下記のようにしている.
- vesting-ci # レポジトリのルート.
- autoload/
| calc.vim # テスト対象コード
+ bundle/ # NeoBundleでinstallするpluginディレクトリ
+ neobundle.vim/ # NeoBundle本体
- vest/ # vestingのテストコード用ディレクトリ
| .vimrc # 2.の設定ファイル
| _runner # 3.のvesting実行マクロ
| calc_add.vim # vestingのテストコードその1
| calc_sub.vim # vestingのテストコードその2
+ vim/
runtest.sh # CLI用シェルスクリプト
.travis.yml # TraviceCI設定ファイル
vestingはカレントディレクトリ配下のvest/*.vim
をテストコードとみなして実行するため, テスト関係のファイルは極力ここに突っ込むようにした.
テスト対象のコードは下記. と言っても只の足し算と引き算.
function! calc#add(a,b)returna:a+a:bendfunctionfunction! calc#sub(a,b)returna:a-a:bendfunction
対応するvestingのテストコードは下記.
scriptencoding utf-8
Context Vesting.run()
It calc#add returns the summation of two values
Should calc#add(1,2)==3
End
End
Fin
vest/calc_sub.vim
も似たような感じ. ちなみに, vestingは:Unite vesting:.
をVimから実行すると, テストの一覧がUnite上に表示されるので, 実行したいテストファイルを選択してEnterを叩くとテストが実行される.
ここからがこのエントリの主眼. まずは上記2. の.vimrc
から.
if has('vim_starting')setnocompatiblelets:basedir = expand('<sfile>:p:h').'/../' " プラグイン自体をruntimepathに登録.
execute('set runtimepath+='.s:basedir) " NeoBundleをruntimepathに登録.
execute('set runtimepath+='.s:basedir.'neobundle.vim') " NeoBundleで依存pluginを記載. " Uniteとvestingは必須.call neobundle#begin(expand(s:basedir.'bundle'))
NeoBundle 'Shougo/unite.vim'
NeoBundle 'Shougo/vesting'call neobundle#end() " 必要なpluginの一括installsilent NeoBundleInstall
endif
Uniteとvestingは最低限必要となるpluginである. もし, 他に必要なpluginがあれば, NeoBundle
を追記していけばよい.
(僕が実際に開発しているPluginでは, vimprocを使ってるいるが, このファイルに追記している)
続いて3.のvesting実行マクロ.
:Unite vesting:.
*
:call unite#action#do('start'):w vest/test_result.log
:quitallvim:ft=vim
vestingを実行した後, *
で全テストファイルを選択. uniteのstart
actionを実行すると, 全テストが実行されて結果がUniteのバッファに表示されるので, これをファイルに保存するようにしている.
あんまりスマートじゃない気もするが, 取り合えず動いてるのでこれでよし.
なお, このファイルの拡張子に.vimを付けてないのは, vestingがテストコードだと誤解しないようにするため.
最後にCLI用のシェルスクリプトとTravisCIの設定ファイル.
実際はディレクトリの存在チェックとか, Vim自体のビルド処理(TravisCIのVimが7.3で古いので)も書いているため, もう少し長くなるのだけど, 先述した方法の骨子を抜きだすとこんな感じだ.
#/bin/shVIMRC_FILE="vest/.vimrc"DRIVER_FILE="vest/_runner"RESULT_FILE="vest/test_result.log"# 1. NeoBundleのクローン
git clone https://github.com/Shougo/neobundle.vim
# 4. Vestingの実行
vim -u ${VIMRC_FILE} -s ${DRIVER_FILE}
cat ${RESULT_FILE}# 5. テスト結果の判定
grep -E "\[Fail\]"${RESULT_FILE}> /dev/null
if[$? -eq 0];thenexit 1
fi
grep -E "\[Error\]"${RESULT_FILE}> /dev/null
if[$? -eq 0];thenexit 1
fi
script:-sh runtest.sh
所感
最初はVim plguinのCI化は結構敷居が高そうに思っていたが, やってみると意外と簡単.
テスティングフレームワークに依存するのはマクロ部分だけなので, vesting以外のフレームワーク使ってる場合でも, 考え方とかシェルは使いまわせる予感.