フォーム読み込み中
REPL(Read-Eval-Print Loop)とは、「入力」「評価」「出力」のループを繰り返すインタラクティブな実行環境のことです。ユーザーがキーボードから式や文を入力すると、即座に評価され、結果が画面に表示されます。このインタラクティブ性により、プログラムの動作を即時に確認できるため、デバッグや試行錯誤に非常に便利です。
しかし、この対話型の特性ゆえに、どうやってテストすればいいのか、と悩まれなことはないでしょうか。
本記事では、REPLの動作を自動でテストするためのシンプルなアプローチを紹介します。ぜひ、プログラムの品質向上にお役立てください。
REPLについて、もう少し説明を加えておきます。
REPLをサポートする処理系が実装されている具体的なプログラミング言語で例示します。
● Rubyのirb(interactive ruby)
$ irb
irb(main):001:0> 1
=> 1
irb(main):002:0> exit
プログラミング言語に限りません。DSLなコマンドでもREPLが使える処理系は多いですね。
● Redis
$ redis-cli
127.0.0.1:6379> SET foo 1
OK
127.0.0.1:6379> SET bar 2
OK
127.0.0.1:6379> GET foo
"1"
127.0.0.1:6379> GET bar
"2"
127.0.0.1:6379> exit
試験方法について解説します。
テスティングフレームワークには、Rubyのminitestを使います。シンプルかつ拡張性もあるため、今回のようなREPLテストの自動化にも最適です。
試験対象のREPLは先の例で示したRedisとします。試験内容も例示した2つのSETとGETにします。
大きな流れは次の通りです。
コードをいったんすべて掲載します。
require 'minitest/autorun'
describe 'Redis client' do
def run_script(commands)
output = []
IO.popen("redis-cli", "r+") do |pipe|
commands.each do |command|
begin
pipe.puts command
rescue Errno::EPIPE
puts "Failed to send command: #{command}"
break
end
end
pipe.close_write
output = pipe.read.split("\n")
end
output
end
it 'sets values' do
result = run_script([
"SET foo 1",
"SET bar 2"
])
assert_equal ["OK", "OK"], result
end
it 'gets values' do
result = run_script([
"GET foo",
"GET bar"
])
assert_equal ["1", "2"], result
end
end
実行します。
$ ruby redis-test.rb
-snip-
Finished in 0.014699s, 136.0670 runs/s, 136.0670 assertions/s.
2 runs, 2 assertions, 0 failures, 0 errors, 0 skips
大事な点を少し掘り下げてみます。Redis CLIに直接コマンドを送る方法としてpopenを使用しています。
IO.popen("redis-cli", "r+") do |pipe|
-snip-
end
popenはサブプロセスを生成し、そのプロセスの標準入出力を制御できる便利なメソッドです。親プロセスとその子プロセス間に、標準入力(STDIN)と標準出力(STDOUT)のパイプラインを確立します。親プロセスから試験したいコマンドを送信し、それを子プロセスで実行します。またその結果を親プロセスへ返す通信となります。
このフロー図を見て、REPL固有の話ではなく、外部コマンドを使う場合と類似のアプローチでは、と思われたかもしれません。その通りです。状態の維持という差異はありますが、サブプロセスを起動して、popenやsystemを使い制御する点は共通です。
親子プロセス間で、入力と出力のファイルディスクリプタを変えてデータを授受するコンピュータの動作原理を思い浮かべれば、そりゃそうだ、という話です。
REPLのインタラクティブ性から、一瞬テストをどうするべきか迷ってしまったのでまとめてみました。開発プロセスの効率向上と品質確保に少しでも貢献できれば幸いです。
条件に該当するページがございません