2018年7月16日

スクリプトライクに GNU Smalltalk を扱う試み #2: SUnit テスティングフレームワークの実行

前回で基本的な実行環境は構築できたため、今回は SUnit によるテスティングフレームワークの実行環境を整えてみようと思う。 SUnit は自分が敬愛するプログラマの一人であるケント・ベック氏によって書かれ、 xUnit フレームワークの原型となったものであり、 Smalltalk コミュニティの先見性をあらわす代表的なフレームワークの一つと言える。

Simple Smalltalk Testing: With Patterns

※ 文脈には関係ないが、ケント・ベック氏著による下記の書籍は、経験上 Smalltalk プログラマに限らず全てのプログラマにお勧めできる良書なので紹介しておきたい(Ruby のような Smalltalk ライクなクロージャの使い方が出来る言語のプログラマには特にお勧めだ)。

ケント・ベックのSmalltalkベストプラクティス・パターン―シンプル・デザインへの宝石集

GNU Smalltalk ではサポートする SUnit パッケージをイメージにロードすることで SUnit が使用可能になる。自分は現在 OS に Linux Mint 18.3 を使っているが、 GNU Smalltalk においては追加の Debian パッケージ(.deb)をインストールしなくても GNU Smalltalk パッケージ(.star)をロード出来た。 CUI 上で動作を確認してみる。

$ gst
GNU Smalltalk ready
(デフォルトイメージで GNU Smalltalk を実行)

st>  PackageLoader fileInPackage: 'SUnit'
(SUnit パッケージを現在のデフォルトイメージにロード)

st> TestCase
TestCase
(SUnit フレームワークの基底クラスである TestCase が定義されている)

gst-load コマンドを使う場合(前回の投稿を参照)は、次のコマンドで指定するイメージファイルに SUnit をロード出来る。

$ gst-load SUnit -I ロードするイメージファイル名

・テストユニットの実行処理

SUnit の動作の確認も兼ねて GNU Smalltalk 環境において CUI で手動で SUnit を実行してみる。

$ gst
GNU Smalltalk ready
(デフォルトイメージで GNU Smalltalk を実行)

st>  PackageLoader fileInPackage: 'SUnit'
( SUnit パッケージを現在のデフォルトイメージにロード)

st> TestCase subclass: #HelloWorldTest
( TestCase クラスを継承した HelloWorldTest テストケースクラスを作成)

st> HelloWorldTest extend [
st> setUp [
st> super setUp
st> ]
st> ]
( TestCase クラスの setUp メソッドをオーバーライド。 これはテストケース内のテストメソッドが実行される前にコンストラクタ(初期化処理)として実行されるメソッドである。テストメソッドが評価される度に呼び出される)

st> HelloWorldTest extend [
st> tearDown [
st> super tearDown
st> ]
st> ]
(TestCase クラスの tearDown メソッドをオーバーライド。これはテストケース内のテストメソッドが実行された後にデストラクタ(後処理)として実行されるメソッドである。テストメソッドが評価される度に呼び出される)

st> HelloWorldTest extend [
st> testHelloWorld [
st> self should: [ 'Hello World' isString ]
st> ]
st> ]
(テストメソッド testHelloWorld を定義する。 SUnit は test で始まる名前のメソッドはテストメソッドとして自動的に実行する便利な機能がある。 should: メソッドは「〜であると期待する」という意味で、引数として与えられたブロックが flase として評価された場合は例外が発生し、テスト失敗となる。この例の場合は true なのでテスト成功)

st> HelloWorldTest extend [
st> testTrueWorld [
st> self assert: true
st> ]
st> ]
(テストメソッド testTrueWorld を定義する。 assert: メソッドは引数の評価が true であればテスト成功となる)

st > HelloWorldTest suite run
2 run, 2 passes
(定義されたテストメソッドのテストを実行。前述したように特に指定しなくても test で始まるメソッドは全て評価されている。定義した2つのテストメソッドが評価され、2つともテスト成功となる)

st> (HelloWorldTest selector: #testHelloWorld) run
1 run, 1 passes
(特定のテストメソッドのみを指定して実行してみる。この場合は testHelloWorld メソッドのみテストされるため、一つの実行で一つの成功となる)

st> | suite |
st> suite := TestSuite named: 'HelloWorldTests'
st> suite addTest: (HelloWorldTest selector: #testHelloWorld)
st> suite addTest: (HelloWorldTest selector: #testTrueWorld)
st> suite run
2 run, 2 passes
(TestSuite クラスを使うとセレクタで指定して追加したテストメソッドをまとめて実行出来る)

こういった処理を自動化出来ればビルド環境は楽になる、と考えられる。

・SUnit での環境を整える

GNU Smalltalk における SUnit の環境を整えるために前回作ったビルドスクリプト(的なもの)に SUnit をサポートする機能を追加する。

gst-package コマンドに使う package.xml ファイルには SUnit で使用するファイルを明示的に定義出来る。定義としては package.xml の <package> の下に

<test>
<sunit>テストスイート名</sunit>
<file>テストスイートが定義された .st ファイル名</file>
<filein>テストスイートが定義された .st ファイル名</filein>
# ~これ以降にも存在するテストスイート定義の .st ファイルが <file> <filein> で定義される
</test>

で定義する。

SUnit の動作を長々と確認したが、実際のところ GNU Smalltalk には SUnit を簡易的に実行出来る gst-sunit コマンドが用意されている。上記のようにテストスイートを定義した package.xml をパッケージングすると、そのパッケージを適用したイメージに対してクラス単位のユニットテストが可能になる。

$ gst-sunit -p 評価するパケージ -I 評価するイメージファイル TestCase *

このコマンドにおいて、最後のオプションで指定されている TestCase * により、指定したパッケージを適用したイメージファイルにおいて、定義されている全てのテストケースを評価出来る( TestCase クラスを継承したクラス下における test で始まるメソッドを全て評価する)。

・上記の結果を踏まえて Atom 上でビルドスクリプト(的なもの)を実行する

結果は前回の結果を上書きする形で GitHub にアップロードしてある。 -t オプションを指定して実行することで SUnit が動作するようになっている。

# 2つのテストメソッドを実行した場合の実行例
$ ./.build.sh -t
Running SUnit
2 run, 2 passes

前回作成したビルドスクリプト(的なもの)に SUnit の評価機能を追加した

0 件のコメント:

コメントを投稿