JMUnitでの作業
JMUnitのセットアップ
JMUnitダウンロードを入手したら、Java MEコンパイラとランタイム環境またはIDEの両方について、2つのJMUnit .jarファイル(「JMUnit4CLDC10.jar」と「JMUnit4CLDC11.jar」)をクラスパス上に配置します。JMUnitの現在のリリースは1.0.2です。
JMUnitのテストケース
JMUnitが提供するフレームワークには2つのバージョンがあり、別々のJARに収められています。1つはCLDC 1.0アプリケーション用で、もう1つは浮動小数点基本型をサポートするCLDC 1.1アプリケーション用です。JUnit流のしきたりでは、JMUnitを使用する適切な単体テストを作成するための最初のステップは、テストケースを作成することです。JMUnitのテストケースを作成するには、JMUnitのjmunit.framework.cldc10.TestCaseまたはjmunit.framework.cldc11.TestCaseを拡張した新しいテストケースクラスを作成しなければなりません。パッケージ名からわかるように、前者は1.0バージョンのサポートを提供し、後者は1.1バージョンのサポートを提供します。両者の違いは、cldc11.TestCaseで実装されているassertEquals()メソッドとassertNotEquals()メソッドがJava浮動小数点基本型をサポートすることだけです(下記を参照)。
JUnitのしきたりでは、テストケースクラスの名前はテスト対象クラスの名前を含み、末尾が「Test」でなければなりません。したがって、先ほどの温度変換クラスのCLDC 1.1バージョンをテストするJMUnitテストケースなら、次のように定義されるでしょう。
public class TemperatureConversionTest extends jmunit.framework.cldc11.TestCase {}
すべてのテストメソッドがテストケースクラスに含まれていなければなりません。JUnitのしきたりにより、テストメソッドの名前は「test」で始まり、その後ろにテスト対象クラス内のメソッドの名前が付きます。たとえば、fahrenheitToCelsiusメソッドをテストするためのテストケースメソッドなら、testfahrenheitToCelsiusとなります。各テストメソッドは期待される結果を「アサート(assert)」しなければなりません。JUnitテストに不慣れな方のために申し上げると、アサートとはメソッドの実行結果がプログラマの期待どおりか否かを検証するステートメントです。JMUnitは次のアサーションをサポートしています。
assertTrue(expression) assertFalse(expression) assertSame(expected, actual) assertNotSame(expected, actual) assertEquals(expected, actual) assertNotEquals(expected, actual) assertNull(object) assertNotNull(object)
JMUnitでは、これらのアサーション呼び出しのいずれかを使用するテストメソッドはAssertionFailedExceptionをスローしなければなりません。フレームワークは、この例外を使って失敗したテストを識別します。適切なテストメソッドを持つTemperatureConversionTestクラスは、次のようになるでしょう。
import jmunit.framework.cldc11.*; public class TemperatureConversionTest extends TestCase { public void testfahrenheitToCelsius() throws AssertionFailedException { System.out.println("fahrenheitToCelsius"); float result = TemperatureConversion.fahrenheitToCelsius(66F); assertEquals(18.88889F, result); } public void testcelsiusToFahrenheit() throws AssertionFailedException { System.out.println("celsiusToFahrenheit"); float result = TemperatureConversion.celsiusToFahrenheit(20F); assertEquals(68F, result); } public void testisHotter() throws AssertionFailedException { System.out.println("isHotter"); assertTrue(TemperatureConversion.isHotter(70F, 2F)); } public void testisCooler() throws AssertionFailedException { System.out.println("isCooler"); assertTrue(TemperatureConversion.isCooler(10F, 10F)); } }
標準のJUnit実装により、JMUnitのテストケース抽象クラスにはsetup()とtearDown()というメソッドも用意されています。これらをオーバーライドして、テストケースを通じたテストの実行の前後にオブジェクトやリソースを初期化したりクリーンアップしたりすることができます。たとえば、Java MEアプリケーションでは、setupでテスト前にレコードストアを開き、tearDownでテスト後にレコードストアを閉じることができます。これらに加え、fail()メソッドでは、アサートステートメントに関係なく、テストメソッドでテストの失敗を返すことができます。このメソッドはテストメソッド内のある種の条件でよく使われます。また、まだ作業が必要なことを示すための方法として、未開発の単体テストをスタブアウトするのにも使用できます。
JMUnitのテストケースクラスにはコンストラクタも付属しています。JMUnitのテストケースクラスのいずれかを拡張したテストケースクラスのコンストラクタは、スーパーコンストラクタを呼び出し、テストケースのテスト数を表す整数とテストケースを識別する文字列を渡さなければなりません。
public TemperatureConversionTest() { super(4, "TemperatureConversionTest"); }
テスト数を表す整数は、テストケースの実際のテスト数と一致していなければなりません。コンストラクタに渡すテスト数と、テストケースの実際のテスト数とを一致させることが大切です。テストケースのtest(int testNumber)メソッドを見ると、これが分かります。
テストケースのtest(int testNumber)メソッドからテストメソッドが始まります。Java MEにはリフレクション機能がないので、JUnitのようにテストメソッドを見つけて自動的に実行することはできません。そのため、テストメソッド内のswitchステートメントに各テストメソッドを追加し、テスト番号に基づいて呼び出す必要があります。TemperatureConversionTestの場合、テストメソッドのコードは次のようになるでしょう。
public void test(int testNumber) throws Throwable { switch(testNumber) { case 0:testfahrenheitToCelsius();break; case 1:testcelsiusToFahrenheit();break; case 2:testisHotter();break; case 3:testisCooler();break; default: break; } }
これがテストケースコンストラクタにテスト数を渡さなければならない理由です。実行時、JMUnitフレームワークはテストケースクラスのインスタンスを作成します。フレームワークはループの中で、0から(テスト数-1)まで、テストケースインスタンスの各メソッドを呼び出します。このようにして、テストメソッドのswitchステートメントの各case(したがって各単体テスト)がフレームワークによって呼び出されます。テストケースにテストメソッドを追加するときにテストケースクラスコンストラクタを更新し忘れると、トリガされないテストケースが出てしまいます。
JMUnitでは開発者自身がテストメソッドを書くので、テストメソッドの実行方法がJUnitとは異なってきますし、おそらくJMUnitの方が柔軟性に優れています。JMUnitではテストメソッドを制御できるため、パラメータを受け取るテストを書くことができます(JUnitではリフレクションを利用するのでこれができません)。たとえば、TemperatureConverstionTestのテストメソッドは次のようになるでしょう。
public void testcelsiusToFahrenheit(float c, float f) throws AssertionFailedException { System.out.println("celsiusToFahrenheit(float c)"); float result = TemperatureConversion.celsiusToFahrenheit(c); assertEquals(f, result); }
こうすると、テストメソッドはパラメータを使って、switchステートメントの中でこのテストメソッドを呼び出すことができます。
public void test(int testNumber) throws Throwable { switch(testNumber) { case 0:testfahrenheitToCelsius();break; case 1:testcelsiusToFahrenheit();break; case 2:testisHotter();break; case 3:testisCooler();break; case 4:testcelsiusToFahrenheit(20F, 68F);break; default: break; } }
JMUnit TestSuite
テストスイートは1つ以上のテストケースを管理します。JMUnitには2つのテストスイート抽象クラス(jmunit.framework.cldc10.TestSuiteとjmunit.framework.cldc11.TestSuite)が用意されているので、これらを拡張してテストスイートを作成します。テストケースの場合と同様に、拡張すべきテストスイートのタイプは、どちらのバージョンのCLDCを使用するかで決まります。CLDC 1.0のアプリケーションにはcldc10.TestSuiteを使用し、CLDC 1.1のアプリケーションにはcldc11.TestSuiteを使用してください。どちらのテストスイート抽象クラスにも、パラメータとして文字列を受け取るコンストラクタがあります。この文字列はテストスイートの説明となります。
テストスイートの機能は、該当するすべてのテストケースのインスタンスを作成し、それらのテストケースのテストメソッドを呼び出すことだけです。テストスイートにテストケースを追加するには、テストスイートの構築時にadd(testCase)メソッドを使用します。変換テストケース用のテストスイートの例を次に示します。
import jmunit.framework.cldc11.TestSuite; public class ConversionTestSuite extends TestSuite { public ConversionTestSuite() { super("All Conversion Tests"); add(new DistanceConversionTest()); add(new TemperatureConversionTest()); } }
JMUnitテストの実行
JMUnitの抽象クラスであるTestCaseとTestSuiteは、MIDletのサブクラスです。これにより、個々のテストケースまたはテストスイートをエミュレータで(または、ありそうもないことですが、実際のデバイスで)実行することができます。シミュレータ上で実行すると、各テストケースまたはテストスイートは、exitとtestという2つのコマンドを提供します。図1は、上述のテストスイートの実行結果を示しています。図2は、失敗がどのように表示されるかを示しています。

テストの実行時にはコンソールもチェックしたいものです(図3を参照)。とりわけ、失敗についてはコンソール出力を見るほうがよくわかります。失敗の出力には、スタックトレース情報と、テストでの実際の値と期待される値が含まれています。これは次に取り上げるJ2MEUnitと比べると、少し見劣りする機能の1つかもしれません。J2MEUnitでは、テストケースの失敗が、コンソール出力の代わりに、エミュレーションデバイス上に実際に表示されます。


