[英]Delphi 7 Dunit checks after StopExpectingException are not working as I expect
下面的代碼工作正常,calc ...生成異常,將其注釋掉或更改calc ...以不拋出異常並且測試失敗。
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);
這兩個方法StartExpectingException
和StopExpectingException
並不是直接調用的。
相反,您應該使用ExpectedException
屬性。 設置此屬性時,將調用StartExpectingException
。 雖然你可以調用StartExpectingException
我相信你預期的用法就是你分配給ExpectedException
。
至於StopExpectingException
,你不要調用它。 框架稱之為。 它在TTestCase.RunTest
中執行,這是執行測試方法的框架代碼。
所以你的測試用例代碼可能如下所示:
ExpectedException := ESomeException;
raise ESomeException.Create(...);
當你聲明你期待一個異常時,你所說的是你的測試方法會引發異常。 由於引發異常會改變控制流,因此引發異常后出現的代碼將不會執行。 異常會在調用堆棧中向上傳播,直到它們被捕獲為止。 該框架將捕獲TTestCase.RunTest
的異常。 如果您已指示捕獲的異常是預期的,則測試將通過,否則將記錄失敗。
所有這一切的最終結果是,如果測試方法的最終行為是提出預期的異常,則可以使用ExpectedException
機制。 如果要在引發異常后執行進一步的測試,則根本不使用ExpectedException
機制。 如果你想這樣做,你應該:
CheckException
。 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
上面調用OuterStep
,第//2
行將在InnerStep
內引發異常。 現在每當出現異常時:
goto
)到調用堆棧中找到的第一個除外或最后一個塊。 Writeln('End');
不會被叫。 //3
行。 OuterStep
的except塊中存在的代碼。 raise;
調用異常,異常重新引發,指令指針跳轉到下一個除了或最后一個塊。 所以當你寫:
StartExpectingException(...);
DoSomething();
StopExpectingException(...);
有兩種可能性:
DoSomething
引發異常,從不調用StopExpectingException
。 DoSomething
不引發異常,當StopExpectingException
被稱為是沒有例外。 David解釋說DUnit框架為您調用StopExpectingException
。 但您可能想知道如何處理檢查多個異常情況的測試用例。
寫小測試。
你知道每個人都說你應該做的事情在任何情況下都是正確的嗎? :)
例如
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;
正如David建議的那樣,您可以在測試中編寫自己的異常處理。 但是你會注意到它會變得有點混亂,在大多數情況下你可能更喜歡選項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! NB! 在選項2中需要注意的一點非常重要。您需要注意您吞下的異常類。 DUnit的
Fail()
方法引發了一個ETestFailure
異常,向框架報告測試失敗。 並且您不希望意外地吞下將導致預期異常的測試失敗的異常。
與細微問題相關的異常測試使得重要的是:首先測試,確保您有正確的失敗,然后才實現生產代碼更改以獲得通過。 該過程將顯着降低啞彈測試的可能性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.