2011-07-25 39 views
6

Đây không phải là một câu hỏi như là một nỗ lực để cứu người khác trong giờ tôi chỉ lãng phí trên PHPUnit.Điều gì sẽ xảy ra với các đối tượng được chuyển giữa các bài kiểm tra PHPUnit phụ thuộc?

Vấn đề của tôi là đối tượng giả của tôi, khi được sử dụng trong thử nghiệm phụ thuộc, không trả lại giá trị mong đợi. Có vẻ như PHPUnit không bảo toàn cùng một đối tượng giữa các thử nghiệm phụ thuộc, mặc dù cú pháp làm cho nó trông giống như nó.

Có ai biết tại sao PHPUnit thực hiện việc này không? Đây có phải là một lỗi? Những điều như thế này trong PHPUnit làm cho nó rất bực bội để sử dụng.

<?php 
class PhpUnitTest 
extends PHPUnit_Framework_TestCase 
{ 
private $mock; 

public function setUp() 
{ 
    $this->mock = $this->getMock('stdClass', array('getFoo')); 

    $this->mock->expects($this->any()) 
     ->method('getFoo') 
     ->will($this->returnValue('foo')); 
} 

public function testMockReturnValueTwice() 
{ 
    $this->assertEquals('foo', $this->mock->getFoo()); 
    $this->assertEquals('foo', $this->mock->getFoo()); 

    return $this->mock; 
} 

/** 
* @depends testMockReturnValueTwice 
*/ 
public function testMockReturnValueInDependentTest($mock) 
{ 
    /* I would expect this next line to work, but it doesn't! */ 
    //$this->assertEquals('foo', $mock->getFoo()); 

    /* Instead, the $mock parameter is not the same object as 
    * generated by the previous test! */ 
    $this->assertNull($mock->getFoo()); 
} 

} 
+0

Vui lòng thêm dòng lệnh bạn đã gọi phpunit khi bạn gặp sự cố. - và có lý do nào khiến bạn làm '$ mock' thành một thành viên tư nhân không? – hakre

+1

AFAIK phpunit chạy phương thức setUp() trước mỗi lần kiểm tra, để reset giá trị $ this-> mock –

+0

Tôi đã dự kiến ​​rằng nó hoạt động như bạn đã viết nó xuống, tôi nghĩ 'setUp()' sẽ không được gọi @ dependant kiểm tra và vì vậy tôi đã thực sự ngạc nhiên rằng điều đó đã thất bại quá ... Điều đó có thể đã cắn tôi BADLY nếu tôi đã có một mô hình thông qua một lớp tôi vượt qua xung quanh với @depends :) – edorian

Trả lời

5

Đối tượng giả trong PHPUnit được đính kèm với cá thể kiểm tra mà chúng được tạo và định nghĩa này theo nghĩa là một phương pháp thử nghiệm duy nhất. Lý do cho điều này là PHPUnit cho phép bạn xác định các kỳ vọng trên một mô hình phải được thỏa mãn trong khi thử nghiệm. Để làm điều này, nó khẳng định những kỳ vọng đó khi phương thức chấm dứt thành công. Nếu giả lập sống trong các thử nghiệm, kỳ vọng sẽ không hiệu quả.

Vấn đề là điều này không hỗ trợ các đối tượng gốc: mocks chỉ chứa các hành động đóng hộp được thực hiện theo các phương thức và đầu vào. Sơ khai không xác nhận rằng các phương thức của chúng được gọi là mock đầy đủ có thể. Có lẽ PHPUnit có thể hưởng lợi từ khả năng tạo ra các sơ khai trong setUpBeforeClass() không được gắn với cá thể kiểm thử.

Tùy chọn khác của bạn là sử dụng thư viện đối tượng mô phỏng bên ngoài chẳng hạn như Mockery hoặc Phake.

Chỉnh sửa: Sau khi xem lại mã mẫu của bạn, tôi tự hỏi tại sao bạn lại ngạc nhiên trước hành vi này. Như Shaunak đã viết, setUp() được gọi trên một cá thể mới trước khi mỗi phương pháp thử nghiệm được thực hiện. Vì vậy, mỗi trường hợp nhận được một mô hình mới stdClass. Nếu bạn muốn chỉ có một phương pháp thử nghiệm để nhận được một kỳ vọng, hãy thêm nó vào chính phương thức thử nghiệm. Bạn vẫn có thể tạo đối tượng giả trong setUp() với bất kỳ hành vi nào sẽ phổ biến đối với tất cả các phương pháp thử nghiệm.

+0

Vì vậy, để rephrase: Sau khi mỗi bài kiểm tra tất cả các đối tượng giả đã được tạo ra trong chạy thử nghiệm được tước của tất cả các 'mong đợi' được giao? – edorian

+0

@David: Lý do tôi nhầm lẫn là cú pháp làm cho nó trông giống như giá trị trả lại của người được ủy quyền được chuyển đến người gửi. Nếu PHPUnit xây dựng lại mọi thứ từ đầu, tại sao nó lại cung cấp cú pháp gây hiểu nhầm này ngay từ đầu? –

+0

@edorian - Kỳ vọng được xác thực, nhưng AFAIK chúng không bị tước. Điều này xảy ra sau khi phương thức thử nghiệm hoàn tất thành công nhưng trước khi gọi 'tearDown()'. Mặc dù bạn có thể thêm nhiều kỳ vọng và cuộc gọi vào mô hình trong 'tearDown()', điều đó sẽ không hữu ích lắm. –

2

Tôi không phải là anh chàng php, vì vậy chính xác cho tôi nếu tôi sai, nhưng tất cả các bài kiểm tra đơn vị được thiết kế để chạy theo thứ tự sau đây,

Setup -> chức năng kiểm tra -> tiêu diệt.

để thiết lập và hủy chức năng được gọi mỗi lần trước khi thực hiện bất kỳ chức năng kiểm tra nào. Điều này được thực hiện với mục đích bảo toàn mục đích thử nghiệm đơn vị.

Nếu bạn muốn có các trường hợp kiểm tra đơn vị phụ thuộc thì bạn phải mã hóa chúng, theo cách đó thay vì tùy thuộc vào các biến toàn cầu để làm điều đó (điều này đánh bại mục đích kiểm tra đơn vị!). Nếu có một trường hợp thử nghiệm 'A' phụ thuộc vào một số hàm, hãy gọi hàm đó từ 'A' và sau đó xác nhận các giá trị.

+0

Phương thức hủy được đặt tên là 'tearDown()'. –

+0

Chính xác! Xin lỗi tôi đã nói chuyện chung chung. – Shaunak