2016-02-23 132 views
11

我要測試不能(或不應該)與響應發送的驗收測試服務器錯誤(快遞),例如與摩卡和Supertest

Error: Can't set headers after they are sent.

捕獲錯誤測試Express錯誤的與錯誤處理程序和5XX代碼響應將提供有價值的反饋在這裏,但問題是頭已被髮送。

這類錯誤可能並不嚴重,很難發現,通常從日誌中計算出來。

該規範是

it('should send 200', function (done) { 
    request(app).get('/').expect(200, done); 
}); 

和測試應用程序是

app.get('/', function (req, res, next) { 
    res.sendStatus(200); 
    next(); 
}); 

app.use(function (req, res) { 
    res.sendStatus(200); 
}); 

什麼是app實例,並要求測試庫(即Supertest)在類似案件快遞之間溝通的最合適的方法是什麼?

問題不限於Supertest。如果有包可以解決Supertest無法解決的問題,那麼也可以考慮它們。

+0

怎麼樣'res.status(500).send()' – walkerrandophsmith

+0

@WalkerRandolphSmith標頭已經由第一個res.sendStatus發送了,這將導致另一個'發送後無法設置標頭'錯誤。 – estus

+0

啊,我想我現在明白了。 – walkerrandophsmith

回答

-2

我使用HAPI而不是Express來做到這一點,但我解決了同樣的問題。我使用外部庫進行調用(如request-promise),並且工作正常。捕捉請求承諾響應中的錯誤。

+1

我不確定你的意思。在示例中,request-promise無法捕獲錯誤,因爲響應本身沒有錯誤 - 它是200.請參閱評論,這已在此處討論。 – estus

1

嘗試只設置狀態碼而不發送它,並避免發送兩次拋出錯誤使用res.status()

由於express documentation

Sets the HTTP status for the response. It is a chainable alias of Node’s response.statusCode .

恕我直言,如果你想檢測它在端至端(E2E)測試工具,如supertest(或),你必須處理快速錯誤併發送正確的輸出(500狀態錯誤,某些消息...)以允許檢測它。

或者改爲使用unit test來測試控制器功能是否使用chai或原生斷言來拋出任何錯誤。

+0

因此,不會發送回復。問題的關鍵在於檢測錯誤,而不是修改應用程序代碼。 – estus

+0

是的,對不起。我剛剛更新了答案。 – Dario

+0

謝謝。關於500錯誤,問題仍然是一樣的 - 一旦200響應被髮送,它不能被改變爲500.並且單元測試應該與其他單元隔離執行。這意味着測試可以通過特定的中間件,但是當幾個中間件堆疊時會導致錯誤。 – estus

1

我回答了類似的問題here。 「無法設置標題後,他們已被設置」的錯誤應通過表達爲未處理的異常。因此,您應該能夠通過該進程引發的unhandledException事件來訪問它。

但是,由於時機的緣故,這比較棘手。您的測試用例的期望函數和完成函數將排隊等待在第一個res.statusCode調用之後的右側的事件循環上處理。不幸的是,接下來的res.statusCode調用可能會在不確定的時間發生。例如,如果第二個路由處理程序調用了非常慢的webservice或db,然後調用res.statusCode,會發生什麼呢?

考慮到這一點,你的選擇很難。蠻力的方法是在測試代碼中等待一段確定的時間,然後檢查。這是有效的,但速度慢,不確定,這會導致你的測試片狀。

另一種選擇是檢查你可能有任何表達的檢測代碼。如果您有快速代碼,可以對各種路由處理程序的進程調用數進行度量,則可以將這些指標公開給測試代碼。然後,您完成測試的條件之一是,在過程路由調用中的所有指標均爲0.第二個選項允許您編寫確定性測試,並且速度更快,因爲您可以輪詢指標。

最後的選擇是通過單元測試來處理這個測試用例。這可能是最好的解決方案,因爲它是確定性的,不需要任何種類的輪詢。然而,缺點是您需要知道您的兩個函數都是按順序調用的,這會導致您嘗試在測試代碼中重新創建用於調用路由處理程序的邏輯。