ちょっとdjUnitで「addReturnValue」を使用しても全く効いてない?という事象に少しハマっていたので原因についてメモしておきます。
addReturnValueが効かない原因
addReturnValueが効かない原因として上げられるのが概ね以下の3つになるかと思います。1と2については少し見なおせばすぐ発見出来そうですが、今回ハマった原因が3でした。。。
- クラス名の指定が間違っている
- メソッド名の指定が間違っている
- 指定したメソッドが複数回実行されている
「指定したメソッドが複数回実行されている」とは
では「指定したメソッドが複数回実行されている」というのはどういう事かというとについて説明します。
根本的な話として以下の2つのコードは全く同じ意味という事を理解しておく必要があります。
|
addReturnValue(UtilClass1.class, "getStr", expected1); setReturnValueAt(UtilClass1.class, "getStr", 0, expected1); |
これだけで気づく方はハッと思うかもしれませんが、ここで重要なのはaddReturnValueでは「1回目に実行」されたメソッドのみしかaddReturnValueで指定した値が返ってこないという事です。つまり「setReturnValueAt」で1回目を指定した場合と同様の動きしかしてくれないのです。
今回私がハマったのは指定したメソッドが想定した箇所よりも手前で事前に実行されていた為、想定したいたメソッドは2回目の実行になっていたために2回目の方にはaddReturnValueが効いていなかったという事象でした。
addReturnValueが効かない時の調査方法
addReturnValueをしてクラス名やメソッド名は正しいのにどうも効いていないように見える時は一度「getCallCount」でメソッドの実行回数を調査して見ると良いかもしれません。
djUnitではメソッドが呼び出されている事の確認は「assertCalled」を使用する事で確認出来ましたが、逆にメソッドを呼び出されていない事の確認では「assertNotCalled」を使用する事で確認出来ます。
Javaソース
djUnitサンプル
djUnitではassertCalledを使用する事でメソッドが呼び出された事が確認出来ます。
Javaソース
djUnitサンプル
複数回呼び出された時の確認方法
以下の様に「getCallCount」を使用する事でメソッドが何回呼び出されたかを確認する事も出来ます。
|
int countHtmlEscape = getCallCount(UtilSample1.class, "htmlEscape"); assertEquals(10, countHtmlEscape); |
djUnitでメソッドの返却値を好みのものに変更する場合は「addReturnValue」メソッドを使用しますが、
同一メソッドを複数回使用していてそれぞれ別々の戻り値に変更したい場合には「setReturnValueAt」メソッドを使用します。
Javaソース
|
public class UtilClass1{ /** * <p>[概 要] サンプルメソッド</p> * <p>[詳 細] </p> * <p>[備 考] </p> * @return 文字列 */ public static String getStr(){ return "hoge"; } } |
|
public class DriverClass1{ /** * <p>[概 要] ドライバーメソッド</p> * <p>[詳 細] </p> * <p>[備 考] </p> */ public static void driverMethod1(){ System.out.println(UtilClass1.getStr()); System.out.println(UtilClass1.getStr()); } } |
djUnitサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
import jp.co.dgic.testing.framework.DJUnitTestCase; import org.junit.Test; public class UtilClassDjUnitTest extends DJUnitTestCase { @Test public void testGetStr2() { // 準備:getStrメソッドの返却値を1回目と2回目で別々の戻り値に変更します。 String expected1 = "test1"; String expected2 = "test2"; setReturnValueAt(UtilClass1.class, "getStr", 0, expected1); setReturnValueAt(UtilClass1.class, "getStr", 1, expected2); // 実行 DriverClass1.driverMethod1(); } } |
実行結果(コンソール)
djUnitを使用する上での最大の利点と言っても良いのがVirtual Mock Objects(仮想モックオブジェクト)が使用出来る事です。
このVirtual Mock Objectsを使用すると作成したクラスでUtilクラスなどのメソッドを使用している場合、使用しているメソッドの戻り値を自由に変更する事が可能となります。
djUnitでメソッドの返却値を好みのものに変更する場合は「addReturnValue」メソッドを使用します。
「addReturnValue」メソッドの使用タイミングとしては、作成したクラスで使用している共通クラスのメソッドなどが未完成の場合でスタブが必要になるケースなどが考えられます。
Javaソース
djUnitサンプル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
import jp.co.dgic.testing.framework.DJUnitTestCase; import org.junit.Test; public class UtilClassDjUnitTest extends DJUnitTestCase { @Test public void testGetStr() { // 準備:getStrメソッドの返却値を好みのものに変更します。 String expected = "test"; addReturnValue(UtilClass1.class, "getStr", expected); // 実行 String result = UtilClass1.getStr(); // 検証 assertEquals("文字列が一致していません。", expected, result); } } |
Javaの勉強をしていると最初の方に学習する事ではあるのですが、ふと違いとは?と考えるとjavaの実行環境と開発環境の違い位の認識しかなかったので整理しておこうと思います。
JDK
- 「Java Development Kit」の略称。
- Javaでプログラムを開発する際に必要。
- ソフトウェア開発キット(SDK)を拡張したサブセット。
- フリーソフトウェア。
JRE
- 「Java Runtime Environment」の略称。
- Javaで作成されたプログラムを実行する場合に必要。
Web開発では帳票をExcelで出力する際に「Apache POI」がよく使用されています。
ただ「Apache POI」を使用する場合、システム的な制限やリソースなど事前に注意しておくべき点があるのでメモしておきます。
Apache POIの問題点
- 「xlsx」形式のファイルの場合、リソースを大量に消費する
POIを使用する場合、出力帳票のテンプレートファイルを用意して帳票を出力するケースが多いと思われます。このテンプレートファイルの拡張子がEXCEL2007以降の形式「xlsx」で用意されている場合、POIでは一旦そのファイルを全てメモリに読み込ませる為により多くのリソース(メモリ)を消費する事になります。
- セル結合処理は非常に遅い
POIでEXCEL操作する場合、セル結合処理は非常に処理速度が遅くなるので帳票のフォーマットを決める場合はセル結合しないフォーマットで設計しておいた方が懸命です。
エディタなどで文字コードを指定する際「BOM有り」と「BOM無し」という選択肢があります。この「BOM」とは何かをまとめておきます。
BOMとは?
まずBOMとは「バイトオーダーマーク (byte order mark) 」の略語となります。
バイトオーダーマークとはUnicode形式のデータを「ビッグエンディアン」、「リトルエンディアン」のどちらで保存しているのかという情報をデータの先頭に付与する情報のことです。
UTF-8の場合、先頭に3バイトのバイナリデータ「0xEF 0xBB 0xBF」が付与されたものが「BOM有り」の状態。付与されていない場合が「BOM無し」の状態となります。
どういう場合に「BOM有り」、「BOM無し」を使い分けるか?
- Unicodeの規格ではBOMは推奨していません。
- Web制作などでHTMLやPHPなどをエディタで編集する際はBOM無しを選択した方が一般的には問題は起こりにくいので無難です。但し、必ずしもBOM無しが正解というわけではないのは認識しておきましょう。
- 「Microsoft Office Excel」などはBOMがないとUTF-8だと認識できず、種々の問題が起こる。
- 基本的にはアプリケーション側でBOM有りが推奨されているケース以外ではBOM無しをデフォルト設定しておけば良いかと思われます。
JUnitでテストする時にprivateメソッドをテストする方法をご紹介します。
privateメソッドをテストするにはリフレクション「java.lang.reflect.Method」を使用することで実行可能となります。
Javaソース
JUnitサンプル
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
|
@Test public void testSampleMethod() { // 準備 SampleClass1 sampleClass1 = new SampleClass1(); String result = ""; // 期待値 String expected = "hogetest"; // 実行 try { Method sampleMethod = SampleClass1.class.getDeclaredMethod("sampleMethod", String.class); // privateメソッドにアクセス可能とする sampleMethod.setAccessible(true); result = (String)sampleMethod.invoke(sampleClass1, "hoge"); } catch (SecurityException e) { // 普通のプログラムでは発生しない、ほとんど無視していい fail(e.getMessage()); } catch (NoSuchMethodException e) { // メソッド名・引数の型が一致しない場合に発生 fail(e.getMessage()); } catch (IllegalArgumentException e) { // 実行対象の引数の型/引数の数があってれば発生しない。NoSuchMethodExceptionの場合と同じく、1度でも通れば基本的に例外処理はいらない fail(e.getMessage()); } catch (IllegalAccessException e) { // 対象メソッドのアクセス制限(private/default package/protected)によりアクセス不可の場合に発生 fail(e.getMessage()); } catch (InvocationTargetException e) { // 対象のメソッドの処理中に発生した例外。e.getCause()で実際にメソッド内で発生した例外を取得できる。 fail(e.getMessage()); } // 検証 assertEquals("戻り値が一致していません", expected, result); } |
「駑馬十駕」 IT系情報を中心に調べた事をコツコツ綴っています。