shellspec README.md 日本語版

shellspecのREADME.mdの日本語版です。

github.com

英語と日本語両方メンテナンスするのが嫌なので、日本語版はなくてもいいかなーとも思っていたんですが、気の迷いで書いちゃいました。(でもリポジトリには入れない予定)

頑張って英語で書いて、それを自分で日本語化するとかいう、なんという無駄感

あ、 Table of Contents のリンクがおかしいけど面倒なので直さないっす。ページ内検索でもしてください。

shellspec

POSIX互換シェルスクリプト用のBDDベースのテスティングフレームワーク

シェルスクリプトをテストしましょう!

f:id:koichi_nakashima:20190311010858p:plain

Table of Contents

イントロダクション

スペックファイル

Describe 'sample' # Example group block
  Describe 'bc command'
    add() { echo "$1 + $2" | bc; }

    Example 'perform addition' # Example block
      When call add 2 3 # Evaluation
      The output should eq 5  # Expectation
    End
  End

  Describe 'implemented by shell function'
    . ./mylib.sh # add() function defined

    Example 'perform addition'
      When call add 2 3
      The output should eq 5
    End
  End
End

特徴

  • POSIX互換シェルに対応 (dash、bash、ksh、busybox等)
  • BDD スタイルのシンタックス
  • シェルスクリプト言語の構文と互換性のあるスペックファイル
  • 純粋なシェルスクリプト実装
  • 最小限の依存関係 (僅かなPOSIX互換コマンドのみ使用)
  • ネスト可能なグループとレキシカルスコープ風のスコープの提供
  • Before / After フック
  • Skip / Pending 機能
  • モックとスタブ (一時的な関数のオーバーライド)
  • 内存の簡易タスクランナー
  • モダンなレポート (カラー対応, エラー行番号表示)
  • 拡張可能なアーキテクチャ (カスタムマッチャー、カスタムフォーマッター等)
  • shellspec は shellspec 自身でテスト

サポートシェル

dash, bash, ksh, mksh, pdksh, zsh, posh, yash, busybox (ash)

動作確認プラットフォーム

  • Linux (ubuntu, debian, alpine)
  • Windows 10 (WSL, cygwin, Git Bash)
  • macOS Mojave
  • Solaris 11

確認済み旧バージョン(このバージョン以降で動作するでしょう)

  • ash 0.3.8 (debian 3.0)
  • dash 0.5.3 (debian 4.0)
  • busybox ash 1.1.3 (debian 4.0)
  • bash 2.03 (debian 2.2)
  • zsh 3.1.9 (debian 2.2)
  • pdksh 5.2.14 (debian 2.2)
  • mksh 28 (debian 4.0)
  • ksh93 93q (debian 3.1)
  • ksh88 0.5.11 (solaris 11)
  • posh 0.3.14 (debian 3.1)
  • yash 2.30 (debian 7)

依存関係

shellspec はシェルスクリプトによって実装されているので、そのため動作に 必要なものはシェルと僅かなPOSIX互換コマンドのみです。

現在使用している外部コマンド

date, mkdir, rm, mv (推奨: printf, ps, readlink, time)

チュートリアル

インストール

shellspec をダウンロードしてPATHにシンボリックリンクを作成するだけです

$ cd /SOME/WHERE/TO/INSTALL
$ wget https://github.com/ko1nksm/shellspec/archive/{VERSION}.tar.gz
$ tar xzvf shellspec-{VERSION}.tar.gz

$ ln -s /SOME/WHERE/TO/INSTALL/shellspec-{VERSION}/shellspec /EXECUTABLE/PATH/
# (例 /EXECUTABLE/PATH/ = /usr/local/bin/, $HOME/bin/)

またはシンボリックリンクを作成するために shellspec を作成します (もし readlink がない場合)

$ cat<<'HERE'>/EXECUTABLE/PATH/shellspec
#!/bin/sh
exec /SOME/WHERE/TO/INSTALL/shellspec-{VERSION}/shellspec "$@"
HERE
$ chmod +x /EXECUTABLE/PATH/shellspec

入門

プロジェクトディレクトリを作成して shellspec --init を実行します。

# プロジェクトディレクトリの作成
$ mkdir <your-project-directory>
$ cd <your-project-directory>

# 初期設定
$ shellspec --init
  create .shellspec
  create spec/spec_helper.sh

# スペックファイルを作成します (好みのテキストエディタを使用できます)
$ cat<<'HERE'>spec/hello_spec.sh
Describe 'hello.sh'
  . lib/hello.sh
  Example 'hello'
    When call hello shellspec
    The output should equal 'Hello shellspec!'
  End
End
HERE

# lib/hello.sh の作成
$ mkdir lib
$ touch lib/hello.sh

# 関数を実装していないため失敗します
$ shellspec

# hello 関数の作成 (好みのテキストエディタを使用できます)
$ cat<<'HERE'>lib/hello.sh
hello() {
  echo "Hello ${1}!"
}
HERE

# 成功します
$ shellspec

サンプル

sample directoryを参照、 shellspec ディレクトリで shellspec sample で実行できます。

基本構造

これらのDSLで構造化された Example を記述できます。

DSL 説明
Describe Example group ブロックを定義します。Example group はネスト可能です。
Context Describe の別名です。
Example Example ブロックを定義します。 この中にexampleを書きます。
Specify Example の別名です。
End Example group または Example ブロックの終了です。
Todo 空の example と同じですが、ブロックではありません。実装予定を示すワンライナー構文です。

ネスト可能なグループとスコープ

スペックファイルは正当なシェルスクリプトの構文ですが、スコープや行番号を実装するために変換処理を行っています。

それぞれの example group ブロック と example ブロックはサブシェルに変換されます。 そのためブロックの中で行われた変更はブロックの外に影響を与えません。

つまりローカル変数とローカル関数をスペックファイルで実現しています。 これは構造化されたスペックを記述するのにとても便利です。

もしどのような変換が行われるのか興味がある場合は、 --translate オプションを使用してください。

一時的なブロックのスキップ

Describe, Context, Example, Specify ブロックの頭に x をつけて xDescribe, xContext, xExample, xSpecify とすることで一時的にブロックの実行をスキップできます。

フック

example の前後に実行されるフックを定義できます。

DSL 説明
Before example 実行前に呼ばれるフックを定義します。
After example 実行後に呼ばれるフックを定義します。

モック と スタブ

現在、shellspec はモックやスタブのための特別な関数は提供していません。 しかしシェル関数を再定義することで既存のシェル関数や外部コマンドをオーバーライドできます。 これをモックやスタブとして代用することが出来ます。

Describe, Context, Example, Specify ブロックがサブシェルで実行されることを思い出してください。 ブロックを抜けた時、オーバーライドした関数は元に戻ります。

Example

example ブロックは、仕様を記述する場所です。 最大一つの Evaluation と 複数の Expectations から構成されます。

Evaluation

検証のためのアクションを定義します。それぞれの Example は 最大一つの Evaluation を記述できます。

When call             echo hello world
     <- evaluation type ->
DSL 説明
When evaluation を定義します。
evaluation type 説明
call シェル関数または外部コマンドを実行します。
invoke シェル関数または外部コマンドをサブシェルで実行します。
run 外部コマンドを実行します。

通常は call を使用することでしょう。 invokecall に似ていますが、サブシェルで実行します。 invokeevaluation のみで関数をオーバーライドしたい 時と exit をトラップしたい時に便利です。

Expectation

検証する内容を定義します。

DSL 説明
The The ステートメントを定義します。
It It ステートメントを定義します。

The ステートメント

これは一番基本的な Expectation です。検証対象(subject)が予想された値であるかを評価(Evaluate)します。

The output        should equal         4
    <- subject ->        <- matcher -> <- expected value ->

modifier は 評価前に subject を加工します。

The line 2  of     output        should equal 4
    <- modofier -> <- subject ->

modifier はつなげることが出来ます。

The word 1 of line 2  of    output        should equal 4
    <- multiple modifier -> <- subject ->

modifier の最初の引数が数値の場合は、代わりに序数を使用することも出来ます。

The second line of output        should equal 4
    <- modofier -> <- subject ->

It ステートメント

It ステートメントThe ステートメント のシンタックスシュガーです。長い主語を避けるために使用できます。

注意: rspecとは違い、ItExample の別名ではありません。

以下の2つの文章は同じ意味です。

The word 1 of line 2 of output should equal 4
It should equal 4 the word 1 of line 2 of output

ランゲージチェイン

shellspec は chai.js に似たランゲージチェインをサポートします。

ランゲージチェインは可読性を上げるためだけのものです。 Expectation の実行には影響を与えません。

  • a
  • an
  • as
  • the

以下の2つの文章は同じ意味です。

The first word of second line of output should valid number
The first word of the second line of output should valid as a number

Subject

検証を行う対象です。

Subject (検証対象) 説明
output
stdout
Evaluation の標準出力を subject として使用します。
error
stderr
Evaluation の標準エラー出力を subject として使用します。
status
exit status
Evaluation の終了ステータスを subject として使用します。
funciton <NAME> 関数実行の標準出力を subject として使用します。
path <PATH>
file <PATH>
dir <PATH>
(別名を解決した) パスを subject として使用します。
value <VALUE>
string <VALUE>
指定した値を subject として使用します。
variable <NAME> 指定した変数の値を subject として使用します。

Modifier

検証を行う対象を加工します。

Modifier 説明
line <NUMBER> subject の指定された行を subject として使用します。
lines subject の行番号を subject として使用します。
word <NUMBER> subject の指定された単語を subject として使用します。
contents ファイルの中身を subject として使用します。 (現在の subject はファイルパスであること)
length subject の長さを subject として使用します。

Matcher

検証を行う処理の内容です。

exit status (subjectは終了ステータスであることを想定)

Matcher 説明
be success 終了ステータスは成功であること
be failure 終了ステータスは失敗であること

stat (subjectはファイルパスであることを想定)

Matcher 説明
be exist ファイルは存在していること
be file ファイルはファイルであること
be directory ファイルはディレクトリであること
be empty ファイルは空であること
be symlink ファイルはシンボリックリンクであること
be pipe ファイルはパイプであること
be socket ファイルはソケットであること
be readable ファイルは読み取り可能であること
be writable ファイルは書込み可能であること
be executable ファイルは実行可能であること
be block_device ファイルはブロックデバイスであること
be charactor_device ファイルはキャラクターデバイスであること
has setgid ファイルは setgid フラグを持っていること
has setuid ファイルは setuid フラグを持っていること

valid

Matcher 説明
be valid number subject は数字として正しいこと
be valid funcname subject は関数名として正しいこと

variable (subject は変数名であることを想定)

Matcher 説明
be defined 変数は定義されていること (set)
be undefined 変数は未定義であること (unset)
be blank 変数は空であること (unset または 空文字)
be present 変数は存在すること (空文字でない文字列)

string

Matcher 説明
start with <STRING> subject は <STRING> で始まっていること
end with <STRING> subject は <STRING> で終わっていること
equal <STRING> subject は <STRING> と一致していること
include <STRING> subject は <STRING> を含んでいること
match <PATTERN> subject は <PATTERN> とマッチすること

other

Matcher 説明
satisfy <FUNCTION> [ARGUMENTS...] subject <FUNCTION> を満たすこと

Helper

DSL 説明
Set 変数に値を代入します。
Unset 変数を未定義にします。
Path
File
Dir
パスの別名を定義します。
Debug デバッグメッセージを出力します

Path alias

読みやすさのために長いパスに短い名前を定義することが出来ます。

Example 'not use path alias'
  The file "/etc/hosts" should be exist
End

Example 'use path alias'
  File hosts="/etc/hosts"
  The file hosts should be exist
End

Skip と Pending

現在実行しているブロックを Skip または Pending します。

DSL 説明
Skip <REASON> 現在のブロックを Skip します。
Skip if <REASON> <FUNCTION> [ARGUMENTS...] 現在のブロックを条件付きで Skip します。
Pending <REASON> 現在のブロックを Pending します。

shellspec コマンド

デフォルトオプションの設定

shellspec コマンドのデフォルトオプションを変更する場合は、オプションファイルを作成します。 以下の順番で読み込みを行い、オプションを上書きます。

  1. $XDG_CONFIG_HOME/shellspec/options
  2. $HOME/.shellspec
  3. ./.shellspec
  4. ./.shellspec-local (VCSで管理しないでください)

タスクランナー

--task オプションでタスクの実行を行います。

環境変数

Name 説明
SHELLSPEC_ROOT shellspec ルートディレクトリ 指定されていない場合は自動的判定します。(もし readlink がない場合は失敗するでしょう)
SHELLSPEC_LIB shellspec lib ディレクトリ 指定されていない場合は $SHELLSPEC_ROOT/lib
SHELLSPEC_LIBEXEC shellspec libexec ディレクトリ 指定されていない場合は $SHELLSPEC_ROOT/libexec
SHELLSPEC_TMPDIR shellspec が使用する一時ディレクトリ 指定されていない場合は $TMPDIR or /tmp
SHELLSPEC_SPECDIR スペックファイルのディレクトリ 現在のディレクトリ下の spec ディレクトリです
SHELLSPEC_LOAD_PATH ライブラリのロードパス $SHELLSPEC_SPECDIR:$SHELLSPEC_LIB:$SHELLSPEC_LIB/formatters

スペックディレクトリ以下の特殊ファイルとディレクトリ

spec/spec_helper.sh

spec_helper.sh--require spec_helper オプションでロードされます。

このファイルは example の実行のための準備を行います。(カスタムマッチャーの定義等)

spec/support/

このディレクトリはカスタムマッチャーやタスクファイルを作成に利用されます。

spec/banner

もし spec/banner ファイルがある場合、shellspec コマンド実行時にバナーを表示します。 バナー表示を無効にする場合は --no-banner オプションを使用します。