Index: [Article Count Order] [Thread]

Date:  Thu, 27 Apr 2000 12:32:46 +0900
From:  firo <firo@....jp>
Subject:  [XP-jp:00274] Re: JUnit 利用方法
To:  extremeprogramming-jp@....jp (extremeprogramming-jp ML)
Message-Id:  <00Apr27.123351jst.115201@....jp>
References:  <B52BD0C8.1178%khosokawa@....com>
Posted:  Thu, 27 Apr 2000 12:33:47 +0900
X-Mail-Count: 00274

矢崎です。

Kaoru Hosokawaさん wrote:

>
> >
> > 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());
> >
> > }
> >
> >
>
>
> > 上のメソッドでは、最初のassertEqualsでエラーがあった場合、
> > そこから先のチェックは行わない。別のメソッドの実行は行う。 
> >
>
> 一つ目のエラーでとまった方がいいような気もしますが、エラーが起きても次のtest
> メソッドを呼ぶようですね。一つ目のエラーでオブジェクトがエラー状態になる可能
> 性があるので、後半のテストは全滅という可能性もありますよね。testごとに新規に
> オブジェクトをnewしたほうがいいのかな?しなくてもいいのかな?
>

ホソカワさんは既にご承知かもしれませんが、JUnitのassertXXX
の動きを以下にまとめました。


assertxxxxは、エラーであると判断した場合には、
AssertionFailedErrorというErrorクラスのサブクラス
のインスタンスを投げるようになっています。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
**AssertionFailedErrorクラス

public class AssertionFailedError extends Error {

  public AssertionFailedError () {
  }

  public AssertionFailedError (String message) {
    super (message);
  }

}


**assertxxxxの例
static public void assert(String message, boolean condition) {
  if (!condition)
     fail(message);
}

static public void fail(String message) {
  throw new AssertionFailedError(message);
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ですから、テストメソッドが以下のようであれば

public void testXXX(){
  aTestTarget.setNumber(5);
  assertEquals(aTestTarget.getNumber(),6);//ここでエラーをあえて発生させてみよ
う!

  aTestTarget.setNumber(1000);
  assertEquals(aTestTarget.getNumber(),1000);
}

2つめのステートメントで例外AssertionFailedErrorが起きて、
そしてここはtry-catch節でくくられていないので、testXXX()
を直ちに終了し、上へ上へと戻っていき、最終的には、
TestResultクラスの以下のメソッドで捕まえられます。


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

public void runProtected(final Test test, Protectable p) {
   try {
        p.protect(); //大雑把に言えば、この中でtestXXXを呼んでいる
   }
   catch (AssertionFailedError e) { //ここでキャッチされる!!
        addFailure(test, e);
   }
   catch (Throwable e) {
        addError(test, e);
   }
}

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
addFailure(test, e)はエラー情報をコレクションに追加している
だけで、テストの実行をとめたり、流れを変えたりとかはしてい
ません。テストが成功しても、失敗しても
1つのrunProtected(final Test test, Protectable p)が終われば、
JUnitは次のテストを開始します。ここで次のテストとは、私の例で
いえば、testXXXが終われば、testYYYを開始するということです。
そして、testYYY用に、あらためて
runProtected(final Test test, Protectable p)が実行されます。


##
さて、ちょっと要約しますと、
testXXX、testYYY、testZZZは前の投稿[XP-jp:00270]で書いたよう
に、まったく他と独立して実行されます。したがって、仮にtestXXXで
assertにひっかかっても、textYYY、testZZZはそれを気にせずに実行
されます。しかしtestXXXの内部で複数のassertxxxを行っている場合、
いずれかのassertxxxでひっかかった場合には、それをtry-catch節
で捕まえないならば、それ以降の処理は行われません。

前置きが長くなりましたが、ホソカワさんのご疑問に対する私の考え
を述べます。

JUnitの上記のような特徴からして、testXXX、testYYY・・・は完全に
独立したテストでなければなりません。これは実行する順番も含めて
です。影響しあうようなメソッドを別々のテストメソッドに書いてはなり
ません。

もし、テストの対象オブジェクトの複数のメソッドをテストする場合で、
かつそれらが影響しあう場合、それは1つのテストメソッドの中で
(例でいえばtestXXXの中だけで)行われなければなりません。その
場合に各メソッドの直後にassertxxxをするかどうかは任意ですが、
基本的にはやっといたほうがいいと思います。つまり、1つめ
のメソッドでエラーになった場合に、それ以降のメソッドが実行できな
くなる場合があるからです。


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

これについては、私の力量ではちょっと簡単にお答えできそうもありま
せん。機会があればまとめてみたいのですが、今回はちょっとご勘弁
ください。もしホソカワさんがJavaを読めるようでしたら、一度
JUnitのソースを追ってみることをお勧めします。

コード量は多くないですし、私の価値観からすると、非常に魅力的な
コードです。Javaで書くプログラムのお手本といっても過言ではないと、
思っています。


--
矢崎博英  firo@....jp