2016-09-06 191 views
2

我正在爲一個庫執行一個測試套件,該庫處理由catch聲明未處理的異常。圖書館收聽墮入全球範圍的事件error(例如window.addEventListener("error", ...))。如何防止摩卡陷入未處理的異常?

但是,如果我想測試它是否爲真的能夠檢測到未處理的異常,我不能因爲Mocha將這些異常視爲測試失敗。我不能用斷言像expect(foo).to.throw,因爲如果我使用這些,那麼異常expect抓住而不再是一個未處理的異常:它不會觸發我的圖書館安裝和我想要的全球監聽器測試。

我試過allowUncaught但這並沒有解決問題。下面是一個重現問題的示例測試:

<!DOCTYPE html> 
<html> 
    <head> 
    <meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8"/> 
    <link href="node_modules/mocha/mocha.css" type="text/css" media="screen" rel="stylesheet" /> 
    <script src="node_modules/mocha/mocha.js"></script> 
    </head> 
    <body> 
    <div id="mocha"></div> 
    <script> 
     mocha.setup('bdd'); 
     mocha.allowUncaught(); 

     it("should be fine", function (done) { 
     // Simulate an error thrown by asynchronous code. 
     setTimeout(function() { 
      throw new Error("error"); 
     }, 100); 

     // My actual error handler is bigger than this. This is just to 
     // simulate what my actual test suite does. 
     function listener(ev) { 
      // Uninstall ourselves. 
      window.removeEventListener("error", listener); 
      done(); // We detected the error: everything is fine. 
     } 
     window.addEventListener("error", listener); 
     }); 

     mocha.run(); 
    </script> 
    </body> 
</html> 

上面的測試應通過。但是,當我運行它時,摩卡報告一次失敗,一次成功!我如何讓Mocha忽略未捕獲的異常並讓我的自定義代碼處理它?

回答

2

摩卡在windowallowUncaught上安裝了自己的未處理的異常事件偵聽器,但並未阻止它。你需要做的是卸載這個處理器搭配:

Mocha.process.removeListener("uncaughtException"); 

這裏是暫時關閉摩卡的未處理的異常處理的例子:

mocha.setup('bdd'); 
    mocha.allowUncaught(); 

    var savedHandler = undefined; 
    before(function() { 
    // Save Mocha's handler. 
    savedHandler = window.onerror; 
    }); 

    describe("without handler", function() { 
    before(function() { 
     // Stop Mocha from handling uncaughtExceptions. 
     Mocha.process.removeListener("uncaughtException"); 
    }); 

    it("should be fine", function (done) { 
     setTimeout(function() { 
     throw new Error("error"); 
     }, 100); 

     function listener(ev) { 
     window.removeEventListener("error", listener); 
     done(); 
     } 
     window.addEventListener("error", listener); 
    }); 

    after(function() { 
     // Restore the handler so that the next tests are treated as 
     // mocha treats them. 
     window.onerror = savedHandler; 
    }); 
    }); 

    describe("with handler", function() { 

    it("should fail", function (done) { 
     setTimeout(function() { 
     throw new Error("error"); 
     }, 100); 
    }); 
    }); 

    mocha.run(); 

第一個測試通過,將只計算一次。正如我們所期望的那樣,第二次測試將失敗,因爲Mocha的未處理異常處理程序已生效。

即使您只有一次測試,您獲得一次合格和一次失敗的原因是摩卡的一個特性。它檢測到未處理的異常,因此它聲明測試失敗。但然後您的代碼調用done所以摩卡宣佈測試已通過並計算兩次。

請注意,以上使用的方法沒有記錄,可能會破壞未來版本的Mocha。據我所知,沒有「官方」方法來獲得理想的結果。

-1

在我看來,你真的是一個設計問題。全局狀態是單元測試的毒藥。您必須擺脫window上的硬編碼依賴關係,以使您的代碼易於測試。

也許你可以讓你的組件接受一個對象來附加自己,在實例化。然後你可以測試任意DOM元素。或者,如果您想要針對窗口對象進行測試,只需傳入不同的窗口對象即可。你可以產生一個子窗口並使用它。摩卡應該可以。 (拿一小撮鹽,我在我的一些測試中創建了子窗口,但我沒有觸發未處理的異常。)

+0

存在真實的生活問題。當我有完整的測試套件和100多個測試時,我不想對套件的結構進行大的修改。我在這裏遇到了兩個完全不同的實現之間的問題。第一個是臨時實現,允許在測試中操作(它與測試代碼合作),以便這裏討論的問題沒有發生。第二個是一個更通用的庫,它不提供相同的靈活性。花了大約10分鐘時間閱讀摩卡的代碼來解決這個問題。 – Louis

+0

我不明白你的第二段會如何工作。根據我的經驗,沒有任何東西允許「任意DOM元素」被通知未處理的異常。哦,他們確實有能力聽到「錯誤」事件,但這些不是由未處理的異常產生的事件。關於第三段,這不是一種不合理的做法。當我從頭建立套件時,我使用了'iframe'元素。他們工作但在任何情況下都不起作用。首先,有一些瀏覽器實現在'iframe'的窗口上偵聽'error'事件只是不起作用。 – Louis

+0

第3段仍然是:還有各種各樣的怪癖執行代碼的測試,必須處理'iframe'中未處理的異常。這讓我回到我的第一個評論:更簡單地關閉Mocha的異常處理,而不是必須爲怪癖修改套件。 – Louis