Vim 8.0 Advent Calendar 22 日目 新しいスタイルのテスト

この記事は [Vim 8.0 Advent Calendar](http://qiita.com/advent-calendar/2016/vim8) の 22 日目の記事です。

Vim 8.0 では、Vim 本体のテストのスタイルが新しくなりました。

## 新しいテストのサンプル

新しいスタイルのテストは Vim 本体のテストのために追加されたものですが、基本的に Vim script の機能であるため、プラグインのテストにも利用できます。
以下に、新しいスタイルで書かれた簡単なテストコードを示します。

```vim
" テスト対象の関数
function! Add(a, b) abort
  return a:a + a:b
endfunction

" --------------------------

function! Test_Add() abort
  call assert_equal(5, Add(2, 3))
endfunction

function! s:run_test() abort
  let v:errors = []

  call Test_Add()

  if empty(v:errors)
    echo 'Test Passed!'
  else
    echo 'Test Failed!'
    for error in v:errors
      echo error
    endfor
  endif
endfunction

call s:run_test()
```

実行すると、以下のようにテストをパスします。

```
Test Passed!
```

テストに失敗する例も示します。`Test_Add()` 関数を以下のように書き換えます。

```vim
function! Test_Add() abort
  call assert_equal(10, Add(2, 3))
endfunction
```

実行すると、以下のようにテストに失敗します。

```
Test Failed!
function <SNR>1_run_test[3]..Test_Add line 1: Expected 10 but got 5
```

## テストの仕組み

以上の例から見て取れるのは 2 点です。

- 値のチェックに使っている `assert_equal()` 関数
- テストの結果のチェックに使っている `v:errors` 組み込み変数

新しいテストでは、これらを使ってテストを書きます。

仕組みは単純です。`v:errors` 組み込み変数は配列です。`assert_` で始まるアサート系の関数を呼び出し、アサートに失敗すると、この `v:errors` に失敗のメッセージが追加されます。

例で行っているように、テスト開始前に `v:errors` を空にし、いくつかのアサート系の呼び出したあと、最後に `v:errors` の中身を確認することでテストを行います。

## アサート系関数

追加されたアサート系の関数を紹介します。
ほとんどの関数は `{msg}` 引数を持っており、これを渡すことで `v:errors` に入るメッセージを指定できます。省略した場合は関数毎に用意されたメッセージが使用されます。

### `assert_equal({expected}, {actual} [, {msg}])`

`{actual}` が `{expected}` と等しい事をテストします。型の自動変換は行われません。

### `assert_notequal({expected}, {actual} [, {msg}])`

`{actual}` が `{expected}` と等しくない事をテストします。

### `assert_inrange({lower}, {upper}, {actual} [, {msg}])`

`{actual}` が `{lower}` 以上 `{upper}` 以下の数値である事をテストします。

### `assert_match({pattern}, {actual} [, {msg}])`

`{actual}` が正規表現 `{pattern}` にマッチする事をテストします。

### `assert_notmatch({pattern}, {actual} [, {msg}])`

`{actual}` が正規表現 `{pattern}` にマッチしない事をテストします。

### `assert_true({actual} [, {msg}])`

`{actual}` が TRUE である事をテストします。ここでの TRUE は、非ゼロの数値か、`v:true` です。それ以外の型や値の場合は失敗します。

### `assert_false({actual} [, {msg}])`

`{actual}` が FALSE である事をテストします。ここでの FALSE は、ゼロの数値か、`v:false` です。それ以外の型や値の場合は失敗します。

### `assert_exception({error} [, {msg}])`

`v:exception` に文字列 `{error}` が含まれている事をテストします。

### `assert_fails({cmd} [, {error}])`

`{cmd}` を実行した結果、エラーが発生する事をテストします。`{error}` が渡された場合、`v:errmsg` に格納されている発生したエラーメッセージに文字列 `{error}` が含まれている事をテストします。

## その他のテスト用関数

assert 系以外で追加されたテストを補助する関数です。ただし、ほとんどの関数は Vim 本体のテストのためのものです。簡単に紹介します。

| テスト用関数                                   | 説明                                  |
|:-----------------------------------------------|:--------------------------------------|
| `test_alloc_fail({id}, {countdown}, {repeat})` | メモリの確保を強制的に失敗させます。  |
| `test_autochdir({expr})`                       | 起動中に 'autochdir' を有効にします。 |
| `test_disable_char_avail()`                    | typeahead なしの状態でテストします。  |
| `test_garbagecollect_now()`                    | 直ちにメモリを解放します。            |
| `test_null_channel()`                          | null のチャンネルを返します。         |
| `test_null_dict()`                             | null の辞書を返します。               |
| `test_null_job()`                              | null の Job を返します。              |
| `test_null_list()`                             | null のリストを返します。             |
| `test_null_partial()`                          | null の部分適用関数を返します。       |
| `test_null_string()`                           | null の文字列を返します。             |
| `test_settime({expr})`                         | Vim が使う内部時間を変更します。      |