2009-10-20 27 views
17

Khi kiểm tra các trường hợp ngoại lệ với PHPUnit, cách tốt nhất để yêu cầu mọi tuyên bố hoặc xác nhận phải ném một ngoại lệ để kiểm tra vượt qua là gì?Làm cách nào để kiểm tra nhiều ngoại lệ với PHPUnit?

tôi về cơ bản muốn làm một cái gì đó như thế này:

public function testExceptions() 
{ 

    $this->setExpectedException('Exception'); 

    foo(-1); //throws exception 
    foo(1); //does not throw exception 

} 

//Test will fail because foo(1) did not throw an exception 

tôi đã đi lên với những điều sau đây, mà không được công việc, nhưng khá xấu xí IMO.

public function testExceptions() 
{ 

    try { 
     foo(-1); 
    } catch (Exception $e) { 
     $hit = true; 
    } 

    if (!isset($hit)) 
     $this->fail('No exception thrown'); 

    unset($hit); 

    try { 
     foo(1); 
    } catch (Exception $e) { 
     $hit = true; 
    } 

    if (!isset($hit)) 
     $this->fail('No exception thrown'); 

    unset($hit); 

} 

Trả lời

16

Vì ngoại lệ là những sự kiện lớn như vậy trong luồng chương trình, nên thử nghiệm nhiều sự kiện trong một thử nghiệm đơn lẻ là vấn đề. Điều đơn giản nhất là chỉ cần chia nó thành hai bài kiểm tra - điều đầu tiên yêu cầu một ngoại lệ để có thể vượt qua, thứ hai chỉ đơn giản là chạy, và sẽ thất bại nó nó đã ném một. Bạn có thể thêm một số bài kiểm tra khác vào thứ hai nếu bạn muốn (xác nhận một giá trị trả về có thể), nhưng tôi muốn nghiêng để chắc chắn nó vẫn chỉ là một điều thiết yếu, theo cách đặt tên của nó. đang

/** 
* @expectedException Exception 
*/ 
public function testBadFooThrowsException() 
{ 
    // optional, can also do it from the '@expectedException x' 
    //$this->setExpectedException('Exception'); 
    foo(-1); //throws exception -- good. 
} 

public function testFooDoesNotThrowException() 
{ 
    foo(1); //does not throw exception 
} 
+1

Tôi chắc chắn thấy quan điểm của bạn, mặc dù nó vẫn cảm thấy hơi lạ khi có nhiều bài kiểm tra khi điểm của mỗi người là đảm bảo rằng một ngoại lệ được ném. – etheros

+3

Bạn cũng có thể sử dụng '@dataProvider annotation' để chuyển các giá trị (và thậm chí cả tên của một ngoại lệ được mong đợi - sử dụng nó với '$ this-> setExpectedException ($ x)'). Việc thêm một giá trị thử nghiệm mới (có thể ném một ngoại lệ) sẽ chỉ là một mục nhập mảng khác trong hàm dataProvider. –

+1

Robert Martin sẽ nói để luôn phân chia các trường hợp thành các xét nghiệm khác nhau. Theo tôi, câu trả lời @AlisterBulman cho thấy giải pháp hoàn hảo cho vấn đề. –

1

Điều này không có ý nghĩa với tôi.

Tôi đoán bạn đang cố gắng thử nghiệm nhiều điều riêng biệt với một trường hợp kiểm tra, đó là thực tiễn không tốt.

Khi foo() ném ngoại lệ dự kiến, trường hợp kiểm tra thành công và bar() sẽ không chạy.

Chỉ cần tạo hai trường hợp thử nghiệm riêng biệt, ít hơn nhiều so với mã bạn đã tạo trong danh sách thứ hai.

Hoặc giải thích lý do tại sao có thể chạy bar(), sau khi foo() không thành công với ngoại lệ, khi nó cũng sẽ ném một ngoại lệ.

+0

Tôi đã thử kiểm tra chức năng tương tự với các đối số khác nhau (và tôi đã chỉnh sửa ví dụ của mình để phản ánh tốt hơn điều này). Một ví dụ trong hướng dẫn sử dụng PHPUnit cho thấy nhiều xác nhận liên quan được thực hiện trong một thử nghiệm duy nhất, vì vậy tôi đã cố gắng sao chép điều này nhưng với các ngoại lệ. – etheros

6

Hơi sạch hơn (nhưng tôi vẫn muốn đề nghị tách các xét nghiệm của bạn:

try { 
    foo(-1); 
    $this->fail('No exception thrown'); 
} catch (Exception $e) {} 
0

Mở rộng về câu trả lời @ dave1010 của, đây là cách tôi giải quyết vấn đề này này cho phép bạn giữ tất cả những ". xác nhận "gọn gàng và gọn gàng trong một thử nghiệm. Bạn chỉ cần xác định một mảng các biến sẽ thất bại trong việc kiểm tra, và sau đó lặp qua từng biến và xem liệu một ngoại lệ có được nâng lên hay không. thử nghiệm đã qua.

<?php 

public function testSetInvalidVariableType() 
{ 
    $invalid_vars = array(
     '',     // Strings 
     array(),   // Arrays 
     true,    // Booleans 
     1,     // Integers 
     new \StdClass  // Objects 
    ); 

    foreach ($invalid_vars as $var) { 
     try { 
      $object->method($var); 
      $this->fail('No exception thrown for variable type "' . gettype($var) . '".'); 
     } catch (\Exception $expected) { 
     } 
    } 
} 
+0

'không' ném' PHPUnit_Framework_AssertionFailedError'. Bạn cần sử dụng các ngoại lệ tùy chỉnh trong mã của mình. – sectus

15

Tôi nghĩ đây là một tình huống rất phổ biến trong thử nghiệm đơn vị. Cách tiếp cận tôi sử dụng trong trường hợp này là sử dụng phpunit dataProviders. Tất cả hoạt động như mong đợi và mã kiểm tra trở nên rõ ràng và súc tích hơn.

class MyTest extends PHPUnit_Framework_TestCase 
{ 
    public function badValues() 
    { 
     return array(
      array(-1), 
      array(1) 
     ); 
    } 


    /** 
    * @dataProvider badValues 
    * @expectedException Exception 
    */ 
    public function testFoo($badValue) 
    { 
     foo($badValue); 
    } 
} 
+2

Ý tưởng rất hay ... kiểm tra nhiều ngoại lệ với một bài kiểm tra. – Andrew

+0

Có nên 'mảng (1)' trong đó không? –

+3

giải pháp đó là đẹp nhất và thanh lịch và phải là câu trả lời được chấp nhận. –

Các vấn đề liên quan