2015-11-02 111 views
2

我正在使用內部框架,每個異常都由錯誤處理程序捕獲並返回適當的JSON錯誤響應,適用於RESTFul API。如何讓PHPUnit停止攔截異常?

然後我有一套測試,這是API測試,主要是測試API返回適當的JSON響應與預期的錯誤代碼。

對於每個測試,都會修改(然後恢復)全局變量以模擬不同的HTTP請求。我這樣做是爲了避免做cURL測試的重載(通過Guzzle或類似的),並且在CLI環境下導致代碼不知道服務器的URL。

<?php 
// ... example, part of a base ApiTestCase class: 

// Override globals (should be backed up by PHPUnit) 
$_SERVER['REQUEST_METHOD']  = $request->method; 
$_SERVER['QUERY_STRING']  = http_build_query($request->parameters); 
$_SERVER['PATH_INFO']   = $request->path; 
$_SERVER['REQUEST_URI']  = $request->path . ($_SERVER['QUERY_STRING'] ? '?' : '') . $_SERVER['QUERY_STRING']; 
$_SERVER['REQUEST_TIME']  = time(); 
$_SERVER['REQUEST_TIME_FLOAT'] = microtime(true); 
$_SERVER['HTTP_COOKIE']  = ''; 

// Set headers, cookies and parameters 
foreach ($request->headers as $k => $v) { 
    $_SERVER['HTTP_' . strtoupper(str_replace('-', '_', trim($k)))] = $v; 
} 
if ($_SERVER['HTTP_COOKIE']) { 
    $GLOBALS['_COOKIE'] = http_parse_cookie($_SERVER['HTTP_COOKIE']); 
} else { 
    $GLOBALS['_COOKIE'] = []; 
} 
$GLOBALS['_REQUEST'] = $request->parameters; 

$responseBody = $app->start(); 

$response->httpCode = http_response_code(); 
$response->body  = $responseBody ? @json_decode($responseBody) : null; 
$response->headers = headers_list(); 

(我知道,改變全局這種方式是不是很好,而框架不應直接依賴於全局,但我仍然是處理遺留代碼。)

於是,就有了這個問題:當我嘗試測試JSON錯誤響應時:PHPUnit攔截拋出的異常(在開始提到的處理程序之前),所以框架沒有機會將其轉換爲JSON並返回正確的響應。

我試圖在PHPUnit手冊中找到某些東西來禁用PHPUnit錯誤處理程序,但沒有運氣。

我能在這種情況下做什麼?謝謝

+0

只需注意,你引用的大部分代碼看起來應該可能在phpUnit測試類的'setup()'函數中。另外請注意,phpUnit具有內置的功能,可在每次測試後將全局恢復爲原始狀態。你可能想要利用它而不是重新發明輪子。 – Simba

+0

這段代碼只是一個例子,但是PHPunit做全局備份的確是這樣。 – itsjavi

+0

@mjolnic您好,我在這裏遇到了完全相同的問題。你有沒有找到合適的解決方案? – dKen

回答

0

只是要清楚,這聽起來像我們實際上並沒有談論捕捉異常在這裏;我們正在討論使用PHP的set_error_handler()截斷致命錯誤,然後終止程序。這將處理錯誤和未捕獲的異常。

你不能做的一件事就是讓那些錯誤和異常落入你的錯誤處理函數 - 正如你已經發現的那樣,phpUnit自己的錯誤處理是你不能覆蓋的(因爲這對phpUnit的工作原理有點基礎)。

你將不得不做的是告訴phpUnit你期待什麼樣的異常或錯誤;根據錯誤是否發生,您的測試將通過或失敗。你不會運行錯誤處理程序,但實際上,你不需要;如果需要,您可以單獨測試功能。對於錯誤條件,您不需要看到錯誤處理程序每​​次都會生成正確的輸出,只是發生會觸發處理程序的錯誤。

對於普通的PHP異常,您可以使用PHPUnit的@expectedException註解你上面的測試功能,像這樣:

/** 
* @expectedException YourExpectedExceptionClass 
*/ 
function testThisWillThrowAnException() { 
    .... 
} 

如果PHP代碼預計將產生一個PHP錯誤(即錯誤,也不例外) ,那麼你會使用相同的想法,但phpUnit提供了一個助手類名稱的錯誤:PHPUnit_Framework_Error。所以,你的代碼應該是這樣的:

/** 
* @expectedException PHPUnit_Framework_Error 
*/ 
function testThisWillProduceAPHPError() { 
    .... 
} 

在這兩種情況下,如果出現預期的錯誤/異常測試將通過。

您還可以測試特定的異常消息和代碼,以防異常類本身不足以讓您知道測試是否完成了您想要的操作。有關更多信息,請參見the phpUnit manual page for annotations

+1

謝謝,問題是我已經在單元測試(它們正在測試源代碼和行爲)中測試這些異常,我不想重複這些。 我在這裏要做的是測試最終響應:客戶端實際得到的是什麼,這在PHPUnit中似乎不可能,而不依賴於cURL,這會減慢測試的執行速度,並且不允許您嘲笑源代碼或數據源。 – itsjavi

0

上面的例子也是正確的,我只提供異常作爲斷言,併爲您提供Exceptions Works的知識。

/** 
* @dataProvider fixturesProvider // its just example 
*/ 
public function testDataIsWrong($fixtures) 
{ 
    try 
    { 
     //Some Code 
     $this->fail('Exception'); 
    } 
    catch(Exception $ex) 
    { 
     $this->assertEquals($ex,'Exception'); 
    } 
} 

這也提供了你的代碼的可能性,你可以測試false或inncorect數據並聲明它是不正確的。

+0

OP想要做的一點是,例外情況已經在他的申請中發現,並在那裏處理。當他的API響應時,所有異常都轉換爲JSON響應,並且他想檢查響應是否正確。將更多的異常處理添加到他的測試中只能處理症狀,但完全沒有考慮到這一點,並且不允許測試作爲目標的JSON響應。 – dKen