著者:後藤大地
コマンドをたくさん作っていくと、いくつかのことに気がつくとおもう。
たとえば作っていくうちにいろいろと思うところがでて、その都度プログラムの書き換えを実施していくと、コマンドの最初のころの動作と最近の動作が異なってしまうことがあるはずだ。こんな感じで互換性が損なわれることにはなにかと問題がある。少なくとも、業務で使おうとした場合には致命的な問題を引き起こしかねない。
もうひとつは終端処理の確認というか、ちゃんとさまざまなケースで動作するのかの確認だ。自分で作るときは自分に都合のよいところしか動作チェックをしないものだ。想定していなかった処理をするとコアダンプが発生してコマンドが異常終了するとかはよくある話だ。こうした問題が発生しないように、ちゃんとテストを行うコードを書いて開発に組み込むというのは大切なことである。
開発の最初の段階からテストフレームワークを入れておくというのはよいアイディアだ。こういうのは最初から導入して、テスト→実装→テスト→実装… といった流れでの開発を常におこなうようにしておきたい。今回はこうしたテストを実施するためのフレームワークとして「Kyua」を紹介しようと思う。
記事本文掲載のシェルスクリプトマガジンvol.49は以下リンク先でご購入できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# pkg install kyua Updating FreeBSD repository catalogue... FreeBSD repository is up to date. All repositories are up to date. The following 3 package(s) will be affected (of 0 checked): New packages to be INSTALLED: kyua: 0.13_2,3 lutok: 0.4_6 atf: 0.21 Number of packages to be installed: 3 The process will require 34 MiB more space. 5 MiB to be downloaded. Proceed with this action? [y/N]: y [1/3] Fetching kyua-0.13_2,3.txz: 100% 4 MiB 835.0kB/s 00:05 [2/3] Fetching lutok-0.4_6.txz: 100% 216 KiB 221.2kB/s 00:01 [3/3] Fetching atf-0.21.txz: 100% 475 KiB 486.2kB/s 00:01 Checking integrity... done (0 conflicting) [1/3] Installing atf-0.21... [1/3] Extracting atf-0.21: 100% [2/3] Installing lutok-0.4_6... [2/3] Extracting lutok-0.4_6: 100% [3/3] Installing kyua-0.13_2,3... ===> Creating users Using existing user 'tests'. Extracting kyua-0.13_2,3: 100%<Paste> # |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
$ brew install kyua ==> Installing dependencies for kyua: atf, lutok, readline, sqlite ==> Installing kyua dependency: atf ==> Downloading https://homebrew.bintray.com/bottles/atf-0.21.sierra.bottle.tar. ######################################################################## 100.0% ==> Pouring atf-0.21.sierra.bottle.tar.gz ==> Using the sandbox 🍺 /usr/local/Cellar/atf/0.21: 114 files, 2.8MB ==> Installing kyua dependency: lutok ==> Downloading https://homebrew.bintray.com/bottles/lutok-0.4.sierra.bottle.tar ######################################################################## 100.0% ==> Pouring lutok-0.4.sierra.bottle.tar.gz 🍺 /usr/local/Cellar/lutok/0.4: 232 files, 1005.5KB ==> Installing kyua dependency: readline ==> Downloading https://homebrew.bintray.com/bottles/readline-7.0.3_1.sierra.bot ######################################################################## 100.0% ==> Pouring readline-7.0.3_1.sierra.bottle.tar.gz ==> Caveats This formula is keg-only, which means it was not symlinked into /usr/local, because macOS provides the BSD libedit library, which shadows libreadline. In order to prevent conflicts when programs look for libreadline we are defaulting this GNU Readline installation to keg-only.. For compilers to find this software you may need to set: LDFLAGS: -L/usr/local/opt/readline/lib CPPFLAGS: -I/usr/local/opt/readline/include ==> Summary 🍺 /usr/local/Cellar/readline/7.0.3_1: 46 files, 1.5MB ==> Installing kyua dependency: sqlite ==> Downloading https://homebrew.bintray.com/bottles/sqlite-3.19.2.sierra.bottle ######################################################################## 100.0% ==> Pouring sqlite-3.19.2.sierra.bottle.tar.gz ==> Caveats This formula is keg-only, which means it was not symlinked into /usr/local, because macOS provides an older sqlite3. If you need to have this software first in your PATH run: echo 'export PATH="/usr/local/opt/sqlite/bin:$PATH"' >> ~/.bash_profile For compilers to find this software you may need to set: LDFLAGS: -L/usr/local/opt/sqlite/lib CPPFLAGS: -I/usr/local/opt/sqlite/include For pkg-config to find this software you may need to set: PKG_CONFIG_PATH: /usr/local/opt/sqlite/lib/pkgconfig ==> Summary 🍺 /usr/local/Cellar/sqlite/3.19.2: 12 files, 2.9MB ==> Installing kyua ==> Downloading https://homebrew.bintray.com/bottles/kyua-0.13.sierra.bottle.tar ######################################################################## 100.0% ==> Pouring kyua-0.13.sierra.bottle.tar.gz 🍺 /usr/local/Cellar/kyua/0.13: 195 files, 39.3MB $ |
1 |
# yum install kyua-cli |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
% kyua help kyua (Kyua) 0.13 Usage: kyua [general_options] command [command_options] [args] Available general options: -c file, --config=file Path to the configuration file; 'none' to disable loading (default: ~/.kyua/kyua.conf or /usr/local/etc/kyua/kyua.conf). -v K=V, --variable=K=V Overrides a particular configuration variable. --loglevel=level Level of the messages to log (default: info). --logfile=file Path to the log file (default: /Users/daichi/.kyua/logs/kyua.20170608-140505.log). Generic commands: about Shows detailed authors and contributors; license; and version information. config Inspects the values of configuration variables. db-exec Executes an arbitrary SQL statement in a results file and prints the resulting table. db-migrate Upgrades the schema of an existing results file to the currently implemented version. A backup of the results file is created, but this operation is not reversible. help Shows usage information. Reporting commands: report Generates a report with the results of a test suite run. report-html Generates an HTML report with the result of a test suite run. report-junit Generates a JUnit report with the result of a test suite run. Workspace commands: debug Executes a single test case providing facilities for debugging. list Lists test cases and their meta-data. test Run tests. See kyua(1) for more details. % |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
-- Kyuafileではハイフンをふたつ並べた部分からが -- コメントとして扱われる。つまり、この説明が -- 書いてある部分はkyua(1)によってコメントとして -- 処理される。 -- シンタックスバージョンはかならず2を指定する -- という決まりになっている。この指定はKyuafile -- の最初にかならず記述することになっている。 syntax(2) -- テストセットにはかならず名前をつける必要がある。 -- これは次のように定義する。 test_suite('suite2') -- あとはATFで開発されたテストプログラムを指定。 -- ここではATFシェルで開発したテストコードを実行 -- したいので、それを指定してある。 atf_test_program{name='atf_tests1.sh'} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
#! /usr/bin/env atf-sh # ATFシェル atf-sh はBourne Shell (/bin/sh)をベースに # 機能を拡張したもので、これを使用する。atf-sh で使用 # できる拡張機能は libatf-sh.subr ファイルに記載されて # いる。 # ATFテストケースは次の手順で定義される。 # # 1. テストケース名を引数としてatf_test_case()を呼び出す # 2. テストケース名_head()、テストケース名_body() を実装する # 3. テストケース名_cleanup() を実装する(任意) # 4. atf_init_test_cases() にテストケースを追加する # # 注意: # ATFテストプログラムではexitやreturnを使うことは禁止され # ている。exitやreturnのような処理が必要な場合はそれように # 用意された atf_pass()、atf_fail()、atf_skip()、atf_check() を # 使用する。これら関数を呼んだ後にはテストケースを終了する # こと。 # # テスト1 # atf_test_case test1 test1_head() { atf_set "descr" "テスト成功処理" } test1_body() { if [ 1 -eq 1 ]; then atf_pass else atf_fail "等価ではない" fi } # # テスト2 # atf_test_case test2 test2_head() { atf_set "descr" "テスト失敗処理" } test2_body() { rm /nonexistentfile } # # テスト3 # atf_test_case test3 cleanup test3_head() { atf_set "descr" "テスト失敗処理" } test3_body() { rm /nonexistentfile if [ $? -ne 0 ]; then atf_fail "/nonexistentfileを削除できません" else atf_pass "/nonexistentfileを削除できません" fi } test3_cleanup() { echo "ここで何らかのクリーンナップ処理" } # # テスト4 # atf_test_case test4 test4_head() { atf_set "descr" "スキップ処理" } test4_body() { atf_skip "このテストをスキップ" } # # 実行するテストケースはすべて atf_init_test_cases() # に追加する。ここに指定されているテストケースが実行の # 対象となる。 # atf_init_test_cases() { atf_add_test_case test1 atf_add_test_case test2 atf_add_test_case test3 atf_add_test_case test4 } |
1 2 3 4 5 6 7 8 9 10 |
% ls atf_tests1.sh Kyuafile % kyua list atf_tests1.sh:test1 atf_tests1.sh:test2 atf_tests1.sh:test3 atf_tests1.sh:test4 % |
1 2 3 4 5 6 7 8 9 10 11 12 |
% kyua test atf_tests1.sh:test1 -> passed [0.008s] atf_tests1.sh:test2 -> failed: Test case body returned a non-ok exit code, but this is not allowed [0.010s] atf_tests1.sh:test3 -> failed: /nonexistentfileを削除できません [0.011s] atf_tests1.sh:test4 -> skipped: このテストをスキップ [0.009s] Results file id is Users_daichi_Documents_shellmagazine_201708_sources_sample01.20170608-141425-880883 Results saved to /Users/daichi/.kyua/store/results.Users_daichi_Documents_shellmagazine_201708_sources_sample01.20170608-141425-880883.db 2/4 passed (2 failed) % |
1 2 3 4 5 6 7 8 9 |
% kyua test atf_tests1.sh:test3 atf_tests1.sh:test3 -> failed: /nonexistentfileを削除できません [0.009s] Results file id is Users_daichi_Documents_shellmagazine_201708_sources_sample01.20170608-141633-969970 Results saved to /Users/daichi/.kyua/store/results.Users_daichi_Documents_shellmagazine_201708_sources_sample01.20170608-141633-969970.db 0/1 passed (1 failed) % |
1 2 3 4 5 6 7 |
% ./atf_tests1.sh test3 atf_tests1.sh: WARNING: Running test cases outside of kyua(1) is unsupported atf_tests1.sh: WARNING: No isolation nor timeout control is being applied; you may get unexpected failures; see atf-test-case(4) rm: /nonexistentfile: そのようなファイルまたはディレクトリはありません failed: /nonexistentfileを削除できません % |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
% kyua report-html Generating html/context.html Generating html/atf_tests1.sh_test3.html Generating html/report.css Generating html/index.html % tree html html ├── atf_tests1.sh_test3.html ├── context.html ├── index.html └── report.css 0 directories, 4 files % |