Vim PluginでもUnit testを回したい!


Vim PluginでもUnit testを回したい!

こんにちは、IKです。
ところで皆さんは毎日Vim scriptを書き、Vim Pluginを公開していると思いますが、
Unit test、したくないですか...?
したいと思ったそこの貴方が今回の対象です!!!

この記事を書く際に、@kamyknさんのspelunker.vimを参考にしています。

用意するもの

以下の3点です

(今回はCircieCIを使った方法を書きます)

テスト導入

今回は自分の作成したPluginにUnit testを導入したので、自分のPluginをベースにUnit testの導入フローを紹介したいと思います。

以下のような、Vimで天気をみるためのPluginのためのUnit testです。

https://github.com/kazukazuinaina/Weather.vim

ディレクトリ構造

.
├── .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についてはこちらに記事がが参考になると思います!

https://thinca.hatenablog.com/entry/20151203/1449076256

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を終了させるスクリプトになっています。

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を終了するところまで自動で回してくれます!
自動化って素晴らしい!!

やっていることとしては、

  1. yumをupdate
  2. 必要なpackage群をインストール
  3. Vimをビルド
  4. pluginをインストール
  5. vimrcをホームディレクトリに配置(もっといい方法あると思います)
  6. 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