Index: [Article Count Order] [Thread]

Date:  Tue, 25 Apr 2000 23:55:09 +0900
From:  Kaoru Hosokawa <khosokawa@....com>
Subject:  [XP-jp:00261] Re: JUnit 利用方法
To:  extremeprogramming-jp@....jp (extremeprogramming-jp ML)
Message-Id:  <B52BD0C8.1178%khosokawa@....com>
In-Reply-To:  <00Apr21.182052jst.115204@....jp>
Posted:  Tue, 25 Apr 2000 23:54:41 +0900
X-Mail-Count: 00261

ホソカワです。ちょっと教えてください。

on 2000/04/21 6:19 PM, firo at firo@....jp wrote:

> 矢崎です。
> 
> Junitの使い方をまとめました。先刻ご承知の方も
> 多かろうとは思いますが、ご勘弁を。
> 
> #なお、JUnitを使う方法にはいろいろバリエーション
> があって、以下はそのうちの1つのやり方です。例え
> ば以下はsuiteメソッドは書いていません。そうしたバ
> リエーションについても後日投稿したいと思います。
> 
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ◇以下のクラスのテストを行うとする。(TestTarget.java)
> 
> public class TestTarget {
> 
> int number;
> String name;
> 
> public TestTarget(){
> name = "";
> }
> 
> public void setNumber(int number){
> this.number = number;
> }
> 
> public int getNumber(){
> return this.number;
> }
> 
> public void setName(String name){
> this.name = name;
> }
> 
> public String getName(){
> return this.name;
> }
> }
> 
> 

例えば、Employee見たいな名前と社員番号を持っているクラスですね。

> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 1.TestCaseのサブクラスを作る(ConcreteTestCase.java)。
> 
> import junit.framework.*;                       //1
> 
> public class ConcreteTestCase extends TestCase{ //1
> }                                               //1
> 
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 2.String型の引数を1つだけ持つ、コンストラクタを作る。
>  引数として受け取った文字列は、このクラスのインスタン
>  スの名前になる。
> 
>  このコンストラクタの中身は、受け取った文字列を引数
>  としてスーパクラスのコンストラクタを呼ぶように書く。
> 
> import junit.framework.*;
> 
> public class ConcreteTestCase extends TestCase{
> 
> public ConcreteTestCase(String name){    //2
> super(name);                      //2
> }                                        //2
> 
> }
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 3.必要ならばsetUpメソッドをオーバライドする。原則的に
>  はオーバライドすることになるでしょう。何をするかというと、
>  ユニットテストをする対象のオブジェクトをnewする。
>  newしたオブジェクトを入れておくためのインスタンス変数
>  も定義する。
> 
> import junit.framework.*;
> 
> public class ConcreteTestCase extends TestCase{
> 
> /*以下の変数は任意。型はテストしたいクラス。数も自由*/
> TestTarget aTestTarget;                  //3
> 
> public ConcreteTestCase(String name){
> super(name);
> }
> 
> /*setUpはリターンはvoid。引数はなしじゃないとだめ。*/
> public void setUp(){                     //3
> aTestTarget = new TestTarget();   //3
> }                                        //3
> 
> }
> 

例えば、setUp()でファイルをオープンしようとして、エラーになった場合、例外で
戻るのでしょうか?どこへ戻るのでしょうか?

> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 4.必要ならばtearDownメソッドをオーバライドする。tearDown
> メソッドは後片付けをするメソッドで、変数に残っているオ
>  ブジェクトを消す。しかしJavaにはガベージコレクション機
>  能があるので、何しなくてもよい(ゆえにオーバライドしな
>  くてよい)。 
> 
> import junit.framework.*;
> 
> public class ConcreteTestCase extends TestCase{
> 
> TestTarget aTestTarget;
> 
> public ConcreteTestCase(String name){
> super(name);
> }
> 
> public void setUp(){
> aTestTarget = new TestTarget();
> }
> 
> /*tearDownはリターンはvoid。引数はなしじゃないとだめ*/
> public void tearDown(){                   //4
> aTestTarget = null;                //4
> //一応nullにしておく //4
> }                                         //4
> 
> }
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 5.Testメソッドを作る。シグニチャは以下のルールに従わなけれ
>  ばならない。
>   
>  1)リターンはvoid。
>  2)引数はなし。
>  3)メソッド名は"test"から始める
> 4)publicでなければならない。
> 
>  それと、メソッド数はいくつでもよい。定義しただけテストが実行さ
>  れる。メソッドの実行順序は不定。(ゆえに、この作業で、新しいイ
>  ンスタンス変数を定義する必要はないと思われる。定義してもい
>  いけど)
>  #ローカル変数は、必要なら定義する。
>  
> import junit.framework.*;
> 
> public class ConcreteTestCase extends TestCase{
> 
> TestTarget aTestTarget;
> 
> public ConcreteTestCase(String name){
> super(name);
> }
> 
> public void setUp(){
> aTestTarget = new TestTarget();
> }
> 
> public void tearDown(){
> aTestTarget = null;
> }
> 
> public void testXXX(){                     //5
> //5
> }                                          //5
> 
> public void testYYY(){                     //5
> //5
> }                                          //5
> 
> public void testZZZ(){                     //5
> //5
> }                                          //5
> 
> }
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 6.各Testメソッドの中身は以下のように作る。
> 
>  1)テストのTargetのオブジェクトの、テストしたいメソッドを
>   呼び出す。
>  2)そのメソッドのリターン値か、あるいはそのメソッドの結果
>   を取得できる別のメソッドを実行し、結果を取得する。
>  3)その結果を判断するassert関連メソッドを呼び出す。
> ※assert関連メソッドは14種類ある。
>    ※14種類のassert関連メソッドで対応できない場合は、
>     独自のassert関連メソッドを作らなければならない。
> 

assertメソッドをリストしていただけますか?

> 
> public void testXXX(){
> 
> int wkInt;
> String unitName;
> 
> aTestTarget.setNumber(0);
> aTestTarget.setNumber(1000);
> wkInt = aTestTarget.getNumber();
> assertEquals(wkInt,1000);
> 
> aTestTarget.setName("TARO");
> assertEquals("TARO",aTestTarget.getName());
> 
> }
> 
> 

テストもシンプルにするべきですから、numberのテストとnameのテストを別々にする
のでしょうね。なぜ、ここでこだわっているのかというと、テストメソッドにコメン
トはつけないのかな?と思っただけです。コメントがあれば、中身を読まなくてすむ
のですが、コメントを付ける暇があるのならrefactoringするのでしょうね。

> 上のメソッドでは、最初のassertEqualsでエラーがあった場合、
> そこから先のチェックは行わない。別のメソッドの実行は行う。 
> 

一つ目のエラーでとまった方がいいような気もしますが、エラーが起きても次のtest
メソッドを呼ぶようですね。一つ目のエラーでオブジェクトがエラー状態になる可能
性があるので、後半のテストは全滅という可能性もありますよね。testごとに新規に
オブジェクトをnewしたほうがいいのかな?しなくてもいいのかな?

> 他のメソッドの例
> 
> public void testYYY(){
> 
> int wkInt;
> String unitName;
> 
> aTestTarget.setNumber(0);
> aTestTarget.setNumber(1000);
> assert(0 != aTestTarget.getNumber());
> 
> aTestTarget.setName("TARO");
> assert(! "HANAKO".equals(aTestTarget.getName()));
> 
> }
> 
> public void testZZZ(){
> assertNotNull(aTestTarget.getName());
> }
> 
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 7.ConcreteTestCase完成。
> 
> import junit.framework.*;
> 
> public class ConcreteTestCase extends TestCase{
> 
> TestTarget aTestTarget;
> 
> public ConcreteTestCase(String name){
> super(name);
> }
> 
> public void setUp(){
> aTestTarget = new TestTarget();
> }
> 
> public void tearDown(){
> aTestTarget = null;
> }
> 
> public void testXXX(){
> 
> int wkInt;
> String unitName;
> 
> aTestTarget.setNumber(0);
> aTestTarget.setNumber(1000);
> wkInt = aTestTarget.getNumber();
> assertEquals(wkInt,1000);
> 
> aTestTarget.setName("TARO");
> assertEquals("TARO",aTestTarget.getName());
> 
> }
> 
> public void testYYY(){
> 
> int wkInt;
> String unitName;
> 
> aTestTarget.setNumber(0);
> aTestTarget.setNumber(1000);
> assert(0 != aTestTarget.getNumber());
> 
> aTestTarget.setName("TARO");
> assert(! "HANAKO".equals(aTestTarget.getName()));
> 
> }
> 
> public void testZZZ(){
> assertNotNull(aTestTarget.getName());
> }
> 
> }
> 
> 

それで、実際にtestXXX(), testYYY(), testZZZ()をコールするのはだれなのでしょ
うか?どのようなメカニズムで呼ばれるのでしょうか?

> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 8.コンパイルし通ったら、実行
> 
>> java junit.ui.TestRunner ConcreteTestCase
>   
> 9.テストが増えるごとに、上の5.6.を行う。
> 
> #もし、間違いあったら教えてください。

-- 
Kaoru Hosokawa
khosokawa@....com