Vim PluginでもUnit testを回したい!
こんにちは、IKです。
ところで皆さんは毎日Vim scriptを書き、Vim Pluginを公開していると思いますが、
Unit test、したくないですか...?
したいと思ったそこの貴方が今回の対象です!!!
この記事を書く際に、@kamyknさんのspelunker.vimを参考にしています。
用意するもの
以下の3点です
- Vim(必須)
- CircleCI (お好みでtravis、ジェンキンスおじさんなどでも良いでしょう)
- 重い腰を上げる勇気
(今回はCircieCIを使った方法を書きます)
テスト導入
今回は自分の作成したPluginにUnit testを導入したので、自分のPluginをベースにUnit testの導入フローを紹介したいと思います。
以下のような、Vimで天気をみるためのPluginのためのUnit testです。
ディレクトリ構造
.
├── .circleci
│ ├── .vimrc
│ └── config.yml
├── .github
│ └── ISSUE_TEMPLATE
│ ├── ISSUE_TEMPLATE.md
│ └── bug_report.md
├── .gitignore
├── LICENCE
├── README.md
├── Weather.gif
├── autoload
│ ├── Weather
│ │ ├── city
│ │ │ ├── Hiroshima.vim
│ │ │ ├── Hukuoka.vim
│ │ │ ├── Kyoto.vim
│ │ │ ├── Nagoya.vim
│ │ │ ├── Osaka.vim
│ │ │ ├── Sapporo.vim
│ │ │ ├── Sendai.vim
│ │ │ ├── Shiga.vim
│ │ │ └── Tokyo.vim
│ │ ├── returncity.vim
│ │ ├── test
│ │ │ ├── test_popup.vim
│ │ │ └── test_status.vim
│ │ └── test.vim
│ └── Weather.vim
├── doc
│ └── Weather.txt
└── plugin
└── Weather.vim
テストコードに関するスクリプトは、test
ディレクトリ内にあるtest_status.vim
と
Weather
ディレクトリ内にあるtest.vim
です。
簡単にこのスクリプトについて紹介しておきます。
- test.vim
これは、testディレクトリに置かれた単体テスト用のスクリプト群をまとめて実行するためのファイルです。
- test_status.vim
これは、apiを叩いた際にhttp statusが正しく返って来ているかをtestするためのスクリプトファイルです。
testコードカキコ
じゃあ実際にtestを書いていきましょう。
test_status.vim
" test_status.vim
let s:dir = expand('<sfile>:h:h') . '/city'
let s:city_data = map(glob(expand(s:dir) . '/*.vim', 1, 1), 'fnamemodify(v:val, ":t:r")')
function! Weather#test#test_status#run()
for i in s:city_data
let l:id = Weather#returncity#return(i)
let l:res = webapi#http#get('http://weather.livedoor.com/forecast/webservice/json/v1?city='.id)
echo i . " status:" . l:res.status
" l:res.statusは文字列だから10進数に変換
call assert_equal(200, str2nr(l:res.status, 10))
endfor
endfunction
test_status.vimは、cityディレクトリにある都市のファイル名を抜き出し、その都市に対応するidを指定してapiをgetで叩き、それをassert_equal
で評価するためのスクリプトになります。
今回のケースだと、call assert_equal(200, str2nr(l:res.status, 10))
の部分がそれに当たり、これはwebapi#http#get('http://weather.livedoor.com/forecast/webservice/json/v1?city='.id)
で返ってきたhttpレスポンスが200
ならヨシ!、そうでないならダメと言う感じになります。
assert_equal
についてはこちらに記事がが参考になると思います!
test.vim
" test.vim
scriptencoding utf-8
let s:save_cpo = &cpo
set cpo&vim
function! Weather#test#run()
" v:errorsを初期化する
let v:errors = []
call Weather#test#test_status#run()
if len(v:errors) >= 1
echo v:errors
" error exit
cquit!
endif
echo 'test success'
qall!
endfunction
let &cpo = s:save_cpo
unlet s:save_cpo
test.vimは、test_status.vimで実行したassert_equalの結果を返し、Vimを終了させるようなスクリプトになっています。
もし、assert_equalを実行し、問題なければ:qa!
でVimを終了、問題があれば:cq!
でVimを終了させるスクリプトになっています。
補足すると、CLIのコマンドの終了ステータスがCIで拾われるので、Vimでもcq!などで正常以外のステータスを送ることでCIの結果を失敗にしたりできます!ってのを使ってます😌 https://t.co/4D3YzM7Otx
— かみけん (@_kamykn_) December 2, 2019
circle ciの設定
testが書けたらあとはcircle ciに丸投げしちゃいましょう!!
version: 2
jobs:
build:
docker:
- image: centos:7
working_directory: ~/project
steps:
- checkout
- run:
name: ls
command: ls -la
- run:
name: yum
command: yum update -y && yum install make gcc ncurses-devel ssh git -y
- run:
name: Build latest Vim
command: git clone https://github.com/vim/vim.git && (cd vim && make && make install)
- run:
name: Vim version
command: vim --version
- run:
name: Install webapi-vim
command: git clone https://github.com/mattn/webapi-vim
- run:
name: write .vimrc
command: mv ~/project/.circleci/.vimrc ~/.vimrc
- run:
name: check path
command: ls -la && pwd
- run:
name: Unit test
command: vim +":call Weather#test#run()"
これで、circle ciくんが自動でVimを起動し、テストを動かし、Vimを終了するところまで自動で回してくれます!
自動化って素晴らしい!!
やっていることとしては、
- yumをupdate
- 必要なpackage群をインストール
- Vimをビルド
- pluginをインストール
- vimrcをホームディレクトリに配置(もっといい方法あると思います)
- Vimを起動し、上記のtest用の関数を呼び出す
これがtest用のvimrcです
scriptencoding utf-8
set encoding=utf-8
syntax enable
set runtimepath+=~/project
set runtimepath+=~/project/webapi-vim
スクリーンショット
テストが成功した図
テストが失敗して絶望している図
最後に
どうでしたか?
これでより豊かなVim lifeが送れることでしょう!
Happy Vimming!!
次の@aiya000さんの記事にも期待です!!
参考文献
https://thinca.hatenablog.com/entry/20151203/1449076256
https://github.com/kamykn/spelunker.vim