今回の学習範囲
自動テストの作成~makeによるビルドまで
目標
テストをシェルスクリプトで書いて、そのテストコードが正しく通ることを確認する
自動テストの作成
#!/bin/bash
assert() {
expected="$1"
input="$2"
./9cc "$input" > tmp.s
cc -o tmp tmp.s
./tmp
actual="$?"
if [ "$actual" = "$expected" ]; then
echo "$input => $actual"
else
echo "$input => $expected expected, but got $actual"
exit 1
fi
}
assert 0 0
assert 42 42
echo OK
上記の内容でtest.shを作成します。
コードの説明
9ccの結果をアセンブルし、実際の結果($actual)を期待されている値($expected)と比較するということを行い、0と42がどちらも正しくコンパイルできることを確認するためのテストです。
- assert関数は引数を二つ受け取ります。
- 入力した値をそのまま返し、$actualに入れます。
./9cc "$input" > tmp.s cc -o tmp tmp.s ./tmp actual="$?"
- 期待する値=$expected(第一引数)と入力した値=$input(第二引数)の実行結果の$actualが等しければ真となります。
test.shに実行権限付与
作成したtest.shファイルは現在以下のようになっています。
オーナーの権限(ファイルの持ち主)は読み取り(Read)と書き込み(Write)のみで実行権限はありません。
権限はls -alF
コマンドで確認できます。
-rw-r--r-- 1 kazu staff 319 9 6 17:52 test.sh
ですのでchmod a+x test.shを実行して実行可能
にします。
x(execute)追加されて実行可能となりました。
-rwxr-xr-x 1 kazu staff 319 9 6 17:52 test.sh*
Macを使用している方へ
同じディレクトリにMakefileというファイル名で作成してください。
毎回dockerコマンドを打つのは正直大変なので、Makefileに記述してコマンドを登録し自動化します。
$ docker run -it -v $HOME/9cc:/9cc -w /9cc compilerbook
Makefile内
CFLAGS=-std=c11 -g -static
9cc: 9cc.c
docker run -it -v ${CURDIR}:/9cc -w /9cc compilerbook cc -o 9cc 9cc.c
test: 9cc
docker run -it -v ${CURDIR}:/9cc -w /9cc compilerbook ./test.sh
clean:
rm -f 9cc *.o *~ tmp*
.PHONY: test clean
- ${CURDIR}は現在のディレクトリの現在のパスを取得します。
- /9cc -w /9ccはdockerのコンテナ内のディレクトリを取得します。
これでmake test
と打つだけでテストを実行できるようになりました!
テストの実行
正しいとき
$ make test
docker run -it -v /Users/kazu/9cc:/9cc -w /9cc compilerbook ./test.sh
0 => 0
42 => 42
OK
エラーを起こさせてみます。assertに渡す引数を以下のように変更します。
assert 0 0
assert 42 123
実行してみましょう。1つ目のassert関数は通りましたが、2つ目のassert関数は偽となりました。
make test
docker run -it -v /Users/kazu/9cc:/9cc -w /9cc compilerbook ./test.sh
0 => 0
123 => 42 expected, but got 123
シェルスクリプトを記述する上での注意
シェルスクリプトはスペースにとても敏感です。
以下のような正しいコードで実行すると '[' 0 = 0 ']'となりますが、
if [ "$actual" = "$expected" ]; then
$expectedの右のスペースをなくすと '[' 0 = '0]'となり、0がシングルクオーテーションに含まれてしまいます。
つまり、0]というコマンドとして認識されてしまうためエラーとなります。
スペースや誤字に気をつけましょう。
やったことまとめ
- シェルスクリプトでテストコードを記述し、挙動の確認をしました。
- Makefileに実行したいコマンドを登録し自動化を行いました。
所感&メモ
自動テストというものは一発で動かして機械的に比較できるくらい簡単なものでいいということでした。難しいことは考えずにとりあえずテストを書くことが大切だということでした。