ウィリアムのいたずらの、まちあるき、たべあるき

ウィリアムのいたずらが、街歩き、食べ物、音楽等の個人的見解を主に書くブログです(たま~にコンピューター関係も)

プリウス、アメリカでも問題になってるみたいだけど。。。

2005-05-24 15:48:59 | Weblog
 ものものさんのブログの記事「走行中にPriusが停止する問題、原因はソフトに」の話って、ウィリアムのいたずらが、5月6日のブログに紹介した、「SoftEther VPN 日記」のトヨタはユーザーをハイブリッドシステムの実験台にしているのか?と同件なのかなあ?

 まあ、同件にしろ、違うにしろ。。。結構、いろいろありそうですね。プリウス

 (って、そもそも、ウィリアムのいたずらは、運転免許もってないから、関係ないんだけどね)


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

引数の値を変えただけのメソッド単位のテストでは、網羅しきれないときのスタブについて

2005-05-24 15:26:37 | 開発ネタ
 トラックバックしていただいたブログをみて、思い出しました!!
 (トラックバックしていただき、ありがとうございますです)
 そうです。そのブログに書かれているとおり、ドライバ作って、そこからメソッドを引数を変えて呼び出すだけでは、できないテストが、あります。


1.メソッドの内部から、他のメソッドを呼び出し、その呼び出しメソッドの帰り値(または引数)を参照して、他のプログラムを起動する場合。引数だけでは制御できないというか、引数がまったくないときがある。

2.DBのデッドロック等、なんらかの例外が発生したときの異常系


 とくに、想定外の例外が発生したときの異常系っていうのが、思わぬバグがおきたときに大事なので、テストする必要があります。

 で、こういうののテストのためには、呼び出される側のスタブを作る必要があるのですが、そのスタブを作るときに、問題があるんです。




たとえば、このクラスをテストするとしますよね。
(yd.readDataが、上記の呼び出される側=スタブが必要)

import java.sql.SQLException;
import java.util.*;

public class ChkCtl1
 {
	public int doTheJob()
	{
		HashMap retHash = new HashMap();
		Job job = new Job();
		
		try
		{
		//	このYobidashiの結果で、処理内容がきまるとき
		//	YobidashiをここでNewして
			Yobidashi yd = new Yobidashi();

			switch(yd.readData(retHash))
			{	//	そのとってきた値を元に、
				//	モデルのクラスをディスパッチしてる場合
			case	1:
				System.out.println("1" + retHash);
				return job.Job1(retHash);
				
			case	2:
				System.out.println("2" + retHash);
				return job.Job2(retHash);
				
			case	3:
				System.out.println("3" + retHash);
				return job.Job3(retHash);
			
			default:
				return -1;
			}		
		}
		//	SQLExceptionがおきることは、想定している
		catch(SQLException e)
		{
			System.out.println("SQLException");
			return -99;
		}
		//	想定外のエラー対応
		catch(Exception e)
		{
			System.out.println(e);
			return -999;
		}
	}
}



さあ、テストするドライバを作りましょう!
っていうことで、
public class TestDriver {
	public static void main(String[] args) {
		ChkCtl1 chk = new ChkCtl1();

		System.out.println("start");
		chk.doTheJob();	
		System.out.println("end");
	}
}


っていうテストドライバをつくっちゃうと、

yobidashiクラスのreadDataメソッドは、
return 1;
として、まず、テストを行い、それがOKだったら、今度は
return 2;
に修正して、それもOKだったら
return 3;
に修正して、それもOKだったら
Exceptionをスローするように修正して。。。
と、大変なのよ!
(今は、3個だから、ぜんぜん大変じゃないけど、ウィリアムのいたずらの作るプログラムなんかだと、このケースが200個以上とかあるものもあって、大変なのよ!)

だから、テストドライバからスタブに、どの値をセットするかを指示しないといけない。。
このテストしようとしているChkCtl1クラスを修正しないで!!
そんなとき、どうするか。




ウィリアムのいたずらの場合、こういう、テストケースの値を持っているクラスを用意してます。

staticにしておくことがみそです!

public class ImaDoko {
	/**	現在のテスト番号	*/
	public static	int	testNo	=	0;

/**
 * セッターだよ。ついでに、セットされたテスト番号も表示
 */
	public static void setTestNo(int no)
	{
		testNo	=	no;
		System.out.println("**********  test NO = " + testNo + "  ***********");
		
	}
	
/**
 * ゲッターだよ。
 */
	public static int getTestNo()
	{
		return testNo;
	}
}



で、ドライバ側は、テスト番号を順番に切り替えて、テストしていくわけ
こんなかんじ
public class TestDriver {

	public static void main(String[] args) {
		ChkCtl1 chk = new ChkCtl1();

		System.out.println("start");
		ImaDoko.setTestNo(1);
		chk.doTheJob();	

		ImaDoko.setTestNo(2);
		chk.doTheJob();	

		ImaDoko.setTestNo(3);
		chk.doTheJob();	

		ImaDoko.setTestNo(4);
		chk.doTheJob();	

		ImaDoko.setTestNo(5);
		chk.doTheJob();	

		System.out.println("End");
	}
}



StaticのtestNoの値を変えているので、他のところから呼び出されても、ちゃんと現在のセットされた値を返すわけだ(うーん、うまく表現できん)

で、スタブ側は、テスト番号に応じて、値を返したり、値をセットしたり、Exceptionをスローする。
/**
 * スタブだよ
 */
public class Yobidashi {
	
	public int readData(HashMap ret) throws SQLException
	{
		
		switch(ImaDoko.getTestNo())
		{
		case	1:
			ret.clear();
			ret.put("komoku1","1");
			ret.put("komoku2","2");
			ret.put("komoku3","3");
			return 1;
			
		case	2:
			ret.clear();
			ret.put("komoku1","12");
			ret.put("komoku2","22");
			ret.put("komoku3","32");
			return 2;

		case	3:
			ret.clear();
			ret.put("komoku1","31");
			ret.put("komoku2","32");
			ret.put("komoku3","33");
			return 3;

		case	4:
			SQLException se = new SQLException();
			throw se;

		case	5:
			RuntimeException e = new RuntimeException();
			throw e;
		}	
		return 99;
	}
}


とくに、想定外のエラーをとるためにExceptionで受け取っている場合っていうのがありますよね。その場合、RuntimeExceptionなら、throwsのところに書いてなくても、スローできるという特性を、case 5:に使っています。




こうすると、テストドライバから流しただけで、ログ(今回はSystem.out.printlnだけど)がとれて、こんな形で、きれいにエビデンスがとれます。


start
********** test NO = 1 ***********
1{komoku3=3, komoku1=1, komoku2=2}
********** test NO = 2 ***********
2{komoku3=32, komoku1=12, komoku2=22}
********** test NO = 3 ***********
3{komoku3=33, komoku1=31, komoku2=32}
********** test NO = 4 ***********
SQLException
********** test NO = 5 ***********
java.lang.RuntimeException
End


で、テスト仕様書に書く項目ですが、
  あるメソッド内部で呼び出して、
  その結果をもとに処理が変化する
といった今回のような場合では、変化するケースぶん、テストをつくることになります。

 で、テストのしかたは、

・テスト番号を持っているクラス(例だとImaDoko)を作成し、
・ドライバからは、そのテスト番号を変えていく。
・スタブでは、そのテスト番号にあった、帰り値その他もろもろを返す。
・テスト仕様書には、そのテスト番号のところに、スタブでどういう値を返すから、結果、なになにが、動くはず!みたいに書く。
・もし、なんだったら、
   テスト仕様書のフリーフォーマットで書く欄に表を作成
   その表に、
      テスト番号、
      スタブで返す値、
      その他、スタブで設定する値
      起動するメソッド(など期待する処理)
 を書いておくと、自動化できるし、そもそも、テスト仕様書が見やすい&書きやすい。

てなかんじでやってます。


  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする