2016-03-20 4 views
4

以下のコードは正常に動作します...例外が生成され、コメントアウトまたは変更されます。Delphi 7 StopExpectingExceptionが期待どおりに機能しないのを確認した後、Dunitがチェックします

StartExpectingException(exception); 
    calcMembersPIPEndDate(EncodeDate(2005,01,01),true); 
    StopExpectingException('calcMembersPIPEndDate - 1st after aDay'); 

私の問題は、この後にこのテスト方法に入れたチェックは実行されないということです。なぜ -
ので

checkEquals(1,0); 
    StartExpectingException(exception); 
    calcMembersPIPEndDate(EncodeDate(2005,01,01),true); 
    StopExpectingException('calcMembersPIPEndDate - 1st after aDay'); 

は、第一checkEquals

StartExpectingException(exception); 
    calcMembersPIPEndDate(EncodeDate(2005,01,01),true); 
    StopExpectingException('calcMembersPIPEndDate - 1st after aDay'); 
    checkEquals(1,0); 

のパスに障害が発生しましたか?

私が使用していますDUNITのどのバージョンを動作するようにしようとしている:

testframework.pas has the following - which didn't seem to 
rcs_id: string = '#(@)$Id: TestFramework.pas,v 1.117 2006/07/19 02:45:55 
rcs_version : string = '$Revision: 1.117 $'; 
versioninfo.inc 
ReleaseNo : array[1..3] of Integer 
      = (9,2,1); 
ReleaseStr  = '9.2.1'; 
ReleaseWhen : array[1..6] of Integer 
      = (2005,09,25,17,30,00); 

答えて

2

StopExpectingExceptionは、あなたが期待するように動作することはできません。理由を確認するには、例外状態での実行の流れを理解することが重要です。

は、次のコードを考えてみましょう:

procedure InnerStep(ARaiseException); 
begin 
    Writeln('Begin'); 
    if ARaiseException then 
    raise Exception.Create('Watch what happens now'); 
    Writeln('End'); 
end; 

procedure OuterStep; 
begin 
    try 
    InnerStep(False); //1 
    InnerStep(True); //2 
    InnerStep(False); //3 
    except 
    //Do something because of exception 
    raise; 
    end; 
end; 

あなたは上記のOuterStepを呼び出すと、ライン//2InnerStep内で例外が発生します。今例外が発生するたびに:

  • コールスタックに見出さ又は最終的ブロックを除いて、第1 各方法gotoような小さな)のうちジャンプ命令ポインタ。
  • Writeln('End');は呼び出されません。
  • //3は呼び出されません。
  • 次に、のブロックOuterStepを除いて、に存在するコードはすべて実行されます。
  • そして最後にraise;が呼び出されたときに、例外が再上昇し、命令ポインタがまたはついにブロックを除いて、次にジャンプします。
  • raiseのようにも注意してください。ブロックを除く内の他の例外もまた飛び出します(最初の例外を効果的に隠す)。

ですから、書くとき:2つの可能性があります

StartExpectingException(...); 
DoSomething(); 
StopExpectingException(...); 

  1. DoSomethingは例外とStopExpectingExceptionが呼び出されることはありません発生します。
  2. DoSomething例外を発生させず、StopExpectingExceptionと指定した場合は、という例外はありません。

David has explainedのDUnitフレームワークはあなたのためのStopExpectingExceptionを呼び出すこと。しかし、複数の例外シナリオをチェックするテストケースにアプローチする方法が不思議に思えるかもしれません。

オプション1

小さなテストを書く。
あなたは誰もがあなたがどんな場合でも正しいことをすると言っていることを知っていますか? :)
など。

procedure MyTests.TestBadCase1; 
begin 
    ExpectedException := ESomethingBadHappened; 
    DoSomething('Bad1'); 
    //Nothing to do. Exception should be raised, so any more code would 
    //be pointless. 
    //If exception is NOT raised, test will exit 'normally', and 
    //framework will fail the test when it detects that the expected 
    //exception was not raised. 
end; 

procedure MyTests.TestBadCase2; 
begin 
    ExpectedException := ESomethingBadHappened; 
    DoSomething('Bad2'); 
end; 

procedure MyTests.TestGoodCase; 
begin 
    DoSomething('Good'); 
    //Good case does not (or should not) raise an exception. 
    //So now you can check results or expected state change. 
end; 

オプション2

ダビデが示唆したように、あなたはテスト中に独自の例外処理を書くことができます。しかし、少し面倒なことに気づくでしょう。ほとんどの場合、オプション1を好むでしょう。特に、明確に名前が付けられたテストによって、何がうまくいかなかったのかを簡単に特定できるという利点があります。

procedure MyTests.TestMultipleBadCasesInTheSameTest; 
begin 
    try 
    DoSomething('Bad1'); 
    //This time, although you're expecting an exception and lines 
    //here shouldn't be executed: 
    //**You've taken on the responsibility** of checking that an 
    //exception is raised. So **if** the next line is called, the 
    //expected exception **DID NOT HAPPEN**! 
    Fail('Expected exception for case 1 not raised'); 
    except 
    //Swallow the expected exception only! 
    on ESomethingBadHappened do; 
    //One of the few times doing nothing and simply swallowing an 
    //exception is the right thing to do. 
    //NOTE: Any other exception will escape the test and be reported 
    //as an error by DUnit 
    end; 

    try  
    DoSomething('Bad2'); 
    Fail('Expected exception for case 2 not raised'); 
    except 
    on E: ESomethingBadHappened do 
     CheckEquals('ExpectedErrorMessage', E.Message); 
     //One advantage of the manual checking is that you can check 
     //specific attributes of the exception object. 
     //You could also check objects used in the DoSomething method 
     //e.g. to ensure state is rolled back correctly as a result of 
     //the error. 
    end; 
end; 

NB!注意!オプション2で注意することは非常に重要です。あなたが呑み込む例外クラスについて注意する必要があります。 DUnitのFail()メソッドは、ETestFailure例外を発生させ、テストが失敗したことをフレームワークに報告します。また、予期しない例外に対してテストの失敗を引き起こす例外を誤って飲み込むことは望ましくありません。

例外テストに関連する微妙な問題は、まずテストし、正しいエラーが発生していることを確認してから、プロダクションコードの変更を実装してパスを取得することです。このプロセスは、ダッジテストの可能性を大幅に低減します。

+1

Dohもちろん、誤ったルーチンを呼び出した後の次の行は決して実行されません.....そして私は例外と最後にすべてのセクションを使って教えます時間。説明と正しい方法 - 両方の答えに感謝します。私は1と2の両方が彼らの場所を持っていることがわかります。 –

4

これらの2つの方法、StartExpectingExceptionStopExpectingExceptionを直接呼び出すことを意味するものではありません。

代わりにExpectedExceptionプロパティを使用することになっています。このプロパティを設定すると、StartExpectingExceptionが呼び出されます。 StartExpectingExceptionと呼ぶことができますが、意図した使用法はExpectedExceptionに割り当てられていると私は信じています。

StopExpectingExceptionについては、電話しません。フレームワークはそれを呼び出します。それはTTestCase.RunTestで、あなたのテストメソッドを実行するフレームワークコードです。

だからあなたのテストケースのコードは次のようになります。

ExpectedException := ESomeException; 
raise ESomeException.Create(...); 

をあなたは例外を期待していることを述べるときは、何を言っていることはあなたの試験方法は、その例外を発生させるということです。例外を発生させると制御フローが変更されるため、例外が発生した後に表示されるコードは実行されません。例外は、キャッチされるまで呼び出しスタックを伝播します。フレームワークはTTestCase.RunTestで例外をキャッチします。キャッチされた例外が予期されると指定した場合、テストは合格します。それ以外の場合は失敗が記録されます。

最終的な結果は、テストメソッドの最終行為が予期される例外を発生させることである場合、ExpectedExceptionメカニズムを使用できることです。例外が発生した後にさらにテストを実行する場合は、ExpectedExceptionメカニズムはまったく役に立ちません。

  1. テスト方法で、例外が設計どおりに発生していることを確認する独自の例外処理コードを記述してください。
  2. CheckExceptionを使用してください。
+0

最初の行に「直接呼び出されることはありません」という意味ですか?私は期待された使用法を見ます。非常に賢明ですね。テストメソッドの数を減らすために、私は一つのテストメソッドにたくさんのテストを入れていました。それらの数は境界テストでした - これは設定されていません。あなたの記述に基づいて、実際には期待される例外を使ってテストメソッドにこれらを入れることは実際にはありません。私はCheckExceptionを調べます –

+0

はい、「直接呼び出すつもりはありません」 –

関連する問題