2013-07-25 48 views
5

我正在爲一項服務開展一些測試自動化工作,並找出一種簡潔的方式將一些常見的設置&驗證卷入「會話」類。如何檢查是否有任何異常已被拋出?

從概念上講,一個測試用例可能是這樣的:

using (var managerSession = new Session(managerRole)) 
{ 
    // A manager puts some items in warehouse 
} 

using (var employeeSession = new Session(employeeRole)) 
{ 
    // An employee moves items from warehouse to store 
} 

using (var customerSession = new Session(customerRole)) 
{ 
    // A customer can buy items from the store 
} 

在Session對象構造我設置爲我和每個角色等適當的認證測試服務的連接,並在會議上的Dispose ()方法我有一個通用的驗證塊,例如,檢查在會話生存期內沒有發生服務器端錯誤或警告。

當然,這是濫用IDispose模式,如果使用塊內的測試代碼引發異常,並且驗證塊也會引發異常,則第二個異常將掩蓋第一個異常。

從概念上講,如果我們有這樣的場景:

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
} 

...和斷言失敗或調用managerSession.DoJob()拋出一個異常,那麼我想會話的Dispose()方法跳過驗證模塊,即

public void Dispose() 
{ 
    if (NoExceptionThrown()) 
    { 
     Assert.IsFalse(this.serviceConnection.HasErrors(), "Service connection has errors"); 
    } 

    this.serviceConnection.Dispose(); 
} 

...這樣的測試方法從來沒有失敗,「服務連接有錯誤」,如果它實際上失敗,「經理沒做工作」,

我的問題是:是否可以在這裏實現'NoExceptionThrown()'方法?是否有一些全局屬性可以檢查,或者可以使用Thread.CurrentThread中隱藏的某些東西?

更新:

我的問題是如何重構這個:-)

我當然可以使用這個模式來代替:

Session.ForRole(managerRole, (session) => { /* Test code here */ }); 

用靜態方法ForRole()如

public static void ForRole(Role r, Action<Session> code) 
{ 
    var session = new Session(r); 
    try 
    { 
     code(session); 
     Assert.IsFalse(session.serviceConnection.HasErrors()); 
    } 
    finally 
    { 
     session.Dispose(); 
    } 
} 

但是我很好奇是否存在某種如上所述的抓取異常狀態的方式。

+2

兩件事。首先,是的,這是濫用'IDisposable'。使用'IDisposable'來表示「我擁有應該儘快釋放的非託管資源」。使其意味着別的東西使你的代碼難以閱讀。其次,你是否擔心*任何*異常,或者只*未被捕獲*異常?假設測試代碼拋出一個異常,捕獲它並正常完成。應該標記? –

+0

啊,我只關心_uncaught_異常。我會更新這個問題...... – Christoffer

+0

至於濫用IDisposable:我實際上更關心的是錯過每次會話的常見驗證,而不是潛在的錯誤掩蓋,所以這個問題更多的是「很高興有」功能。實際的測試代碼塊包含10-100行UI自動化代碼,並且我們已經發現缺陷未被發現,因爲驗證步驟中的一個在其中一個塊中錯過了(或報告在錯誤的塊中)。 – Christoffer

回答

1

這本來是有益的,如果有歷時Exception類型的參數來表示什麼異常,如果有的話,是在用其清理相關的finally方面懸而未決的IDisposable.Dispose過載。雖然Dispose方法通常不應該關心例外的細節,但在應該向呼叫方報告的方法期間可能出現條件。從Dispose中拋出的任何異常都會替換調用者的finally上下文中未處理的任何異常,所以如果Dispose方法可以在替換之前封裝未決的異常,將會有所幫助。不幸的是,沒有這樣的功能存在,我不希望有任何添加。

雖然有些黑客可能用於實現類似所需的效果,但唯一符合語義的方法是將例外作爲Dispose方法的參數。任何其他方法的問題是Dispose可能在多個嵌套finally塊內運行,其中一些塊有未決的異常,其中一些沒有;檢查執行上下文以確定嵌套最深的finally塊的狀態的代碼可能會失敗,如果該塊不是保護被丟棄對象的生命週期的塊。

+0

我想我會接受這個答案作爲最正確的答案 – Christoffer

0

好吧,一個確定的,但醜陋的方法是在你的課堂上有一個布爾(默認爲false)。

using (var managerSession = new Session(managerRole)) 
{ 
    Assert.IsTrue(managerSession.DoJob(), "Manager did not do his job"); 
    managerSession.NoExceptionThrown = true; 
} 

我不認爲你會比你的IDisposable模式更清潔。

在這種情況下,try ... catch ...可能會更好,因爲您可以直接訪問異常對象,您可以測試它是否爲null(這是一個單詞嗎?甚至存儲它以備後用。你不應該失去任何東西,因爲using最終只是一個嘗試抓住糖。

+1

是的,無效是一個完美的詞。 – Christoffer

+0

而對於更嚴重的說法,在Dispose方法中設置控制驗證塊的屬性實際上並不是一個好主意。如果我們在每個使用塊上添加一些東西,那麼最好將現有的驗證代碼重構爲一個單獨的方法,並在關閉範圍之前調用該方法 – Christoffer

+0

@Christoffer是的,我想你正在嘗試做一個使用圓形插入方孔的東西。正如supercat指出的那樣,正確的方法是傳遞異常對象或者是否有處理異常的指示。所以,我想你可以添加適當的方法,只是拋棄使用並自己調用Dispose(exception)?那裏也存在一些問題,我認爲你不能強迫這種語言按照你喜歡的方式去做,而不去掉它,並且向後重新貼上它的頭:c。據我所知,沒有辦法檢查catch塊之外的任何異常。 – Xcelled194