2012-12-18 24 views
21

Phương pháp setUp()tearDown() được gọi trước và sau mỗi lần kiểm tra. Nhưng thực sự, là có bất kỳ ví dụ từ thực sự về lý do tại sao tôi cần điều này?Bất kỳ ví dụ từ thực nào về cách setUp() và tearDown() nên được sử dụng trong PHPUnit?

Kiểm tra kiểm tra người khác, tôi luôn luôn nhìn thấy cái gì đó như:

public function setUp() 
{ 
    $this->testsub = new TestSubject(); 
} 

public function tearDown() 
{ 
    unset($this->testsub); 
} 

public function testSomething() 
{ 
    $this->assertSame('foo', $this->testsub->getFoo()); 
} 

Tất nhiên, có hầu như không có sự khác biệt giữa cách này và cách biến cục bộ "cũ".

+0

Sự khác biệt là bạn chỉ cần thiết lập mã một lần, dù có bao nhiêu bài kiểm tra có trong lớp thử nghiệm của bạn –

+0

@MarkBaker như vậy ... chỉ Ví dụ: khi tạo chủ thể thử nghiệm, yêu cầu nhiều dòng? – gremo

+0

Một ví dụ điển hình là thiết lập một bảng cơ sở dữ liệu và phá hủy nó một lần nữa khi kết thúc thử nghiệm. – busypeoples

Trả lời

16

Nếu bạn thực hiện mọi phương pháp thử nghiệm riêng lẻ, mã kiểm tra của bạn sẽ chia sẻ nhiều dòng chỉ đơn giản là tạo đối tượng cần kiểm tra. Mã chia sẻ này có thể (nhưng không NÊN) đi vào phương pháp thiết lập.

Mọi thứ cần được thực hiện để tạo đối tượng cần kiểm tra sau đó cũng đi vào phương pháp thiết lập, ví dụ tạo đối tượng giả được chèn vào hàm tạo của đối tượng thử nghiệm.

Không có điều gì cần phải được rớt xuống vì cuộc gọi tiếp theo để thiết lập sẽ khởi tạo biến thành viên lớp với một tập hợp các đối tượng mới.

Điều duy nhất cần teardown là nếu thử nghiệm của bạn để lại một cái gì đó đằng sau vĩnh viễn, như các tệp đã tạo hoặc các mục cơ sở dữ liệu. Nó thực sự không phải là một ý tưởng tốt để viết các bài kiểm tra mà làm những việc như vậy, nhưng tại một số điểm bạn không thể trừu tượng nữa và phải chạm vào các công cụ như đĩa cứng, cơ sở dữ liệu hoặc mạng thực.

Vì vậy, có rất nhiều thiết lập nhiều hơn teardown cần thiết, và tôi luôn luôn xóa phương pháp teardown nếu không có công việc phải được thực hiện cho thử nghiệm này.

mocks Về, tôi làm việc như thế này:

private $_mockedService; 
private $_object; 
protected function setUp() 
{ 
    $this->_mockedService = $this->getMock('My_Service_Class'); 
    $this->_object = new Tested_Class($this->_mockService); 
} 

public function testStuff() 
{ 
    $this->_mockedService->expects($this->any())->method('foo')->will($this->returnValue('bar')); 
    $this->assertEquals('barbar', $this->_object->getStuffFromServiceAndDouble()); 
} 
+1

Cảm ơn bạn đã làm rõ về 'tearDown()' ... – gremo

+0

tearDown() bị thiếu ở đây, nhưng về cơ bản bạn sẽ bỏ đặt bất kỳ thứ gì cần xóa, tương tự như trình mô tả . –

+1

@StevenScott Không, 'teardown()' là cố ý KHÔNG trong mã của tôi, bởi vì 'setUp()' sẽ ghi đè lên bất cứ điều gì anyway. Không cần viết hàm teardown để viết 'NULL' cho bất kỳ thuộc tính riêng nào của lớp kiểm tra đó. – Sven

4

Bạn có thể khởi tạo một loạt các đối tượng cố định và để chúng có sẵn dưới dạng các biến mẫu trong mỗi thử nghiệm thay vì xây dựng chúng riêng lẻ cho từng thử nghiệm.

Bạn có thể tạo các tài nguyên như xử lý tệp trong thiết lập rồi đảm bảo bạn đóng chúng trong tearDown. Nếu bạn đang viết các tệp tạm thời, bạn có thể chắc chắn rằng bạn xóa chúng. Nếu bạn mở một kết nối cơ sở dữ liệu, bạn có thể đóng nó (mặc dù bạn có thể muốn làm điều đó ở nơi khác - setupBeforeClass/tearDownAfterClass được gọi cho mọi tệp thử nghiệm, không phải cho mọi trường hợp thử nghiệm.)

Nó chỉ là móc trước/sau đó là một điều hấp dẫn để nói chung. Sử dụng nó để làm cho cuộc sống của bạn dễ dàng hơn, hoặc không sử dụng nó.

+2

+1 cho "Sử dụng nó để làm cho cuộc sống của bạn dễ dàng hơn hoặc không sử dụng nó. " setUp() chỉ là một công cụ tái cấu trúc, để chia sẻ mã _common_. Chỉ sử dụng nó khi nó có ý nghĩa; không ép buộc tất cả các vật cố định phải đi vào đó, vì thường thì mỗi bài kiểm tra cần một vật cố hơi khác! –

1

Bạn có thể sử dụng hầu như bất cứ lúc nào bạn sẽ có một sự phụ thuộc trong lớp bạn đang thử nghiệm. Một ví dụ điển hình về điều này có thể là một số loại đối tượng lưu trữ trạng thái ứng dụng (một đối tượng phiên, một giỏ mua hàng, v.v.).

Ví dụ: tôi có một lớp học sẽ tính chi phí giao hàng trên nội dung của giỏ hàng được xác định bởi đối tượng giỏ hàng. Và giả sử giỏ hàng này được chuyển vào lớp tính toán giao hàng thông qua việc tiêm phụ thuộc. Để kiểm tra hầu hết các phương thức của lớp bạn có thể cần thực sự khởi tạo một đối tượng giỏ hàng và đặt nó trong lớp để kiểm tra đơn vị các phương thức khác nhau của bạn. Bạn cũng có thể cần phải thêm các mục vào giỏ hàng ass tốt. Vì vậy, bạn có thể có một thiết lập như sau:

public function setUp() 
{ 
    $this->cart = new cart(); 
    $this->cart->add_item('abc'); 
    $this->cart->add_item('xyz'); 
} 

Hãy giả sử phương pháp thử nghiệm của bạn thực sự có thể sửa đổi các mặt hàng của giỏ hàng, trang trí chúng với thông tin chi phí giao hàng. Bạn không muốn thông tin từ một thử nghiệm chảy máu vào tiếp theo, vì vậy bạn chỉ cần bỏ giỏ hàng ở cuối.

public function tearDown() 
    unset($this->cart); 
} 
+0

Bạn cần khởi tạo MOCK của giỏ hàng sẽ trả lại chỉ các giá trị bạn cần để kiểm tra phép tính trong lớp của bạn. Việc thiết lập một giỏ hàng thực sự có thể quá phức tạp vì phụ thuộc của chính nó và bạn không thể kiểm tra xem giỏ hàng đã được gọi với đúng các tham số và phương thức hay chưa. – Sven

+0

@Sven Tôi đồng ý rằng một giỏ hàng giả sẽ thực sự là tốt nhất ở đây. Tôi đã cố gắng minh họa một cách đơn giản một trường hợp sử dụng sẽ đưa ra một ý tưởng về tiện ích của 'setUp()' và 'tearDown()' mà không cần phải giới thiệu một khái niệm thử nghiệm đơn vị cao cấp hơn nữa. Có lẽ tôi đã không chọn ví dụ tốt nhất ở đây :) –

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