広告

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
                      2010年10月17日

    Java総合講座 - 初心者から達人へのパスポート
                  vol.205

                                セルゲイ・ランダウ
 バックナンバー: http://www.flsi.co.jp/Java_text/
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


-------------------------------------------------------
・現在、このメールマガジンは以下の2部構成になっています。
[1] 当初からのコース:vol.xxx(xxxは番号)が振られています。
   これは現在、中級レベルになっています。
[2] 2009年11月開講コース:xxx号(xxxは番号)が振られています。
   これは現在、初心者向けのレベルになっています。
・このメールマガジンは、画面を最大化して見てください。
小さな画面で見ていると、不適切な位置で行が切れてしまう
など、問題を起すことがあります。
・このメールマガジンに掲載されているソース・コード及び
文章は特に断らない限り、すべて筆者が著作権を所有してい
ます。また、これらのソース・コードは学習用のためだけに
提供しているものです。
-------------------------------------------------------


========================================================
◆ 01.Strutsのアプリケーション開発(プロジェクト:StrutsShop)
========================================================

さて、以前vol.190で作成したValueLogStringMaker(ログ出力の支援
のためのクラス)を少し修正しておきましょう。

jp.co.flsi.lecture.reflectパッケージのValueLogStringMaker.javaを
下記のように修正してください。(プロジェクト・エクスプローラーの中の
「StrutsShop」(これはプロジェクト名である)の配下の「Javaリソース: src」
の配下のjp.co.flsi.lecture.reflect(これはパッケージ名である)の配下の
ValueLogStringMaker.javaを開いて編集する)

--------------------------------------------------------
package jp.co.flsi.lecture.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;

public class ValueLogStringMaker {
   StringBuffer buffer = null;

   public String getValues(String variableName, Object object) {
      buffer = new StringBuffer();
      buffer.append(variableName + " = [\n");
      appendObject(variableName, object);
      buffer.append("]");
      return buffer.toString();
   }

   private void appendFields(Object object) {
      Class clazz = object.getClass();
      buffer.append(clazz.getName());
      buffer.append("@" + Integer.toHexString(object.hashCode()) + "[\n");
      Field[] fieldList = clazz.getDeclaredFields();
      for (Field field : fieldList) {
         appendProperty(field.getName(), field.getType().getName(), object);
      }
      buffer.append("]");
   }

   private void appendProperty(String fieldName, String fieldType, Object object) {
      String getterMethodName = null;
      // publicなgetメソッドを持つフィールド(プロパティー)のみをアペンドする。
      // ただし、boolean型のgetメソッドはisで始まるものとする。
      if (fieldType.equals("boolean")) {
         getterMethodName = "is" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
      }
      else {
         getterMethodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
      }
      Method method = null;
      try {
         method = object.getClass().getMethod(getterMethodName, new Class[0]);
      } catch (SecurityException e) {
         // アクセスできないgetメソッドは無視する。
         return;
      } catch (NoSuchMethodException e) {
         // getメソッドのないものは無視する。
         return;
      }
      Object result = null;
      try {
         result = method.invoke(object, new Object[0]);
      } catch (IllegalArgumentException e) {
         // 呼び出せないgetメソッドは無視する。
         return;
      } catch (IllegalAccessException e) {
         // 呼び出せないgetメソッドは無視する。
         return;
      } catch (InvocationTargetException e) {
         // 呼び出せないgetメソッドは無視する。
         return;
      }
      buffer.append("   " + fieldName + " = ");
      appendObject(fieldName, result);
   }

   private void appendObject(String fieldName, Object value) {
      if (value == null) {
         buffer.append("null");
      }
      else if (value instanceof Collection) {
         append(fieldName, (Collection) value);
      } else if (value instanceof Map) {
         append(fieldName, (Map) value);
      } else if (value instanceof long[]) {
         append(fieldName, (long[]) value);
      } else if (value instanceof int[]) {
         append(fieldName, (int[]) value);
      } else if (value instanceof short[]) {
         append(fieldName, (short[]) value);
      } else if (value instanceof byte[]) {
         append(fieldName, (byte[]) value);
      } else if (value instanceof char[]) {
         append(fieldName, (char[]) value);
      } else if (value instanceof double[]) {
         append(fieldName, (double[]) value);
      } else if (value instanceof float[]) {
         append(fieldName, (float[]) value);
      } else if (value instanceof boolean[]) {
         append(fieldName, (boolean[]) value);
      } else if (value.getClass().isArray()) {
         append(fieldName, (Object[]) value);
      } else {
         append(fieldName, value);
      }
      buffer.append("\n");
   }

   private void append(String fieldName, Collection value) {
      Object[] array = value.toArray();
      buffer.append("{\n");
      for (Object element : array) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, Map value) {
      Collection col = value.values();
      Object[] array = col.toArray();
      buffer.append("{\n");
      for (Object element : array) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, long[] value) {
      buffer.append("{\n");
      for (long element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, int[] value) {
      buffer.append("{\n");
      for (int element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, short[] value) {
      buffer.append("{\n");
      for (short element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, byte[] value) {
      buffer.append("{\n");
      for (byte element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, char[] value) {
      buffer.append("{\n");
      for (char element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, double[] value) {
      buffer.append("{\n");
      for (double element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, float[] value) {
      buffer.append("{\n");
      for (float element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, boolean[] value) {
      buffer.append("{\n");
      for (boolean element : value) {
         buffer.append("   " + element + "\n");
      }
      buffer.append("}");
   }

   private void append(String fieldName, Object[] value) {
      buffer.append("{\n");
      for (Object element : value) {
         buffer.append("   ");
         appendObject(fieldName, element);
      }
      buffer.append("}");
   }

   private void append(String fieldName, Object value) {
      if ((value instanceof String) ||
            (value instanceof Long) ||
            (value instanceof Integer) ||
            (value instanceof Short) ||
            (value instanceof Byte) ||
            (value instanceof Character) ||
            (value instanceof Double) ||
            (value instanceof Float) ||
            (value instanceof Boolean)) {
         buffer.append(value);
      } else {
         appendFields(value);
      }
   }

}
--------------------------------------------------------

以前とどこが違うのか、わかりますね。
どこをどう修正したのか、各自が考えて下さい。
(ヒント:余計なエラー・メッセージを出力している箇所があったので、
出力しないように書き換えた。)



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


さて、今回はStrutsのアプリケーションの単体テスト(unit test)について
お話しましょう。


単体テストといえば、以前(vol.160〜vol.161で)JUnitについてお話しました。
JUnitはJavaの単体テストをするための定番ツールで、これを使えば単体テストが
非常に楽になるはずなのですが、ちょっと困ったことにStrutsのアプリケーション
の単体テストはJUnitでは簡単には行えません。

たとえば、ItemListActionのexecute()メソッドをテストしようと思ったら、
その引数(ActionMapping mapping, ActionForm form,
 HttpServletRequest request, HttpServletResponse response)
の各オブジェクトを事前に自前で用意しなければならない羽目になり、
これはかなり面倒です。

しかし、さいわいにもStruts専用の単体テスト・ツールとして、StrutsTestCase
(これもやはりオープン・ソース)という、JUnitを拡張したツールが提供
されており、これを使えば面倒が解消されます。

という訳で、今回からStrutsTestCaseの使い方についてお話していきます。
(もちろんStrutsTestCaseもEclipseで使っていきます。)



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、まずはStrutsTestCaseのダウンロード(無料)&インストール作業からです。

(1) Webブラウザー(Internet Explorer)で下記のWebページにアクセスします。

http://sourceforge.net/projects/strutstestcase/

(2) このWebページの中の
「Download Now!」
というボタンをクリックします。(ボタンには
「strutstest214-1.2_2.4.zip (2.7MB)」
というサブタイトル(説明書き)が書かれているはず
なので確認しておいてください。)

あとは画面に従ってダウンロードして下さい。

(3) ダウンロードしたファイル(strutstest214-1.2_2.4.zip)を解凍します。
(Webブラウザーはもう用がないので閉じておきましょう。)

(4) 解凍してできたフォルダーの中に

strutstest-2.1.4.jar

というファイル(これがStrutsTestCaseの本体)があるはずですので、これを
Eclipseのワークスペースの

C:\JavaWorkSpace\StrutsShop\WebContent\WEB-INF\lib

の配下にコピーしましょう。

以上でStrutsTestCaseのインストールは終わりです。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


では、Eclipseを起動しましょう。

以下の手順でテスト・ケースのクラスを作成します。

(1) プロジェクト・エクスプローラーの中の「StrutsShop」(プロジェクト)
配下の「Javaリソース: src」配下のjp.co.flsi.lecture.struts(パッケージ)
配下のItemListActionを右クリックし、「新規」→「その他」を選択します。

(2) 「新規」ウインドウにおいて、「Java」配下の「JUnit」配下の
「JUnitテスト・ケース」を選択し、「次へ」ボタンをクリックします。

(3) 「JUnitテスト・ケース」ウインドウでは、「新規JUnit 3テスト」が
選択されていることを確認し、「次へ」ボタンをクリックします。

(4) 「使用可能なメソッド」欄の中で、ItemListAction配下のexcecute()メソッド
にチェック・マークを入れ(その左側の四角い枠の中をクリックするとチェック・マーク
が入る。このとき同時にその上層のItemListActionにもチェック・マークが自動的
に入る)、「完了」ボタンをクリックします。

(5) 「JUnit 3がビルド・パスにありません。追加しますか?」と聞いてきますので、
そのまま「OK」ボタンをクリックします。


┌補足─────────────────────────┐
以前vol.160では、パッケージ・エクスプローラーの中で、
プロジェクトを右クリックし、「ビルド・パス」→
「ライブラリーの追加」を選択して「JUnit」を選択(クリック)
するという操作を行いましたが、上の(5)の操作がこの
「ライブラリーの追加」の操作の代わりになります。
└───────────────────────────┘


さて、これでItemListActionTestというクラスが自動生成されましたね。
これを使えばItemListActionの単体テストを行うことができます。
(現在のままだと、このItemListActionTestクラスは単にJUnitのテスト・ケース
に過ぎませんが、これからこれをStrutsTestCase用に書き換えていきます。)


その前に、ちょっと注意しておくことがあります。
StrutsTestCaseでは、Tomcatを起動せずに単体テストを行いますので、
Tomcatの起動が前提になっている部分を少し手直ししておく必要があります。
それを先にやっておきましょう。



◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆ ◆


(次回に続く)



┏━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
★ホームページ:
      http://www.flsi.co.jp/Java_text/
★このメールマガジンは
     「まぐまぐ(http://www.mag2.com)」
 を利用して発行しています。
★バックナンバーは
      http://www.flsi.co.jp/Java_text/
 にあります。
★このメールマガジンの登録/解除は下記Webページでできます。
      http://www.mag2.com/m/0000193915.html
★このメールマガジンへの質問は下記Webページにて受け付けて
 います。わからない所がありましたら、どしどしと質問をお寄
 せください。
      http://www.flsi.co.jp/Java_text/
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Copyright (C) 2010 Future Lifestyle Inc. 不許無断複製