2008-11-10 18 views
107

Tôi đã có một PHPUnit mock object trả về 'return value' không có vấn đề gì đối số của nó:Làm thế nào tôi có thể nhận được PHPUnit MockObjects để trả về các giá trị khác nhau dựa trên một tham số?

// From inside a test... 
$mock = $this->getMock('myObject', 'methodToMock'); 
$mock->expects($this->any)) 
    ->method('methodToMock') 
    ->will($this->returnValue('return value')); 

Những gì tôi muốn để có thể làm là trả lại một giá trị khác nhau dựa trên những lập luận truyền cho phương thức giả. Tôi đã thử một cái gì đó như:

$mock = $this->getMock('myObject', 'methodToMock'); 

// methodToMock('one') 
$mock->expects($this->any)) 
    ->method('methodToMock') 
    ->with($this->equalTo('one')) 
    ->will($this->returnValue('method called with argument "one"')); 

// methodToMock('two') 
$mock->expects($this->any)) 
    ->method('methodToMock') 
    ->with($this->equalTo('two')) 
    ->will($this->returnValue('method called with argument "two"')); 

Nhưng điều này gây ra PHPUnit để phàn nàn nếu giả không được gọi với đối số 'two', vì vậy tôi cho rằng định nghĩa của methodToMock('two') ghi đè định nghĩa những người đầu tiên.

Vì vậy, câu hỏi của tôi là: Có cách nào để lấy đối tượng giả lập PHPUnit trả về một giá trị khác dựa trên các đối số của nó không? Và nếu vậy, làm thế nào?

Trả lời

99

Sử dụng gọi lại. ví dụ. (ngay từ tài liệu PHPUnit):

<?php 
class StubTest extends PHPUnit_Framework_TestCase 
{ 
    public function testReturnCallbackStub() 
    { 
     $stub = $this->getMock(
      'SomeClass', array('doSomething') 
     ); 

     $stub->expects($this->any()) 
      ->method('doSomething') 
      ->will($this->returnCallback('callback')); 

     // $stub->doSomething() returns callback(...) 
    } 
} 

function callback() { 
    $args = func_get_args(); 
    // ... 
} 
?> 

Thực hiện bất kỳ việc xử lý nào bạn muốn trong hàm gọi lại() và trả lại kết quả dựa trên $ arg của bạn khi thích hợp.

+1

Bạn có thể cung cấp liên kết tới tài liệu không? Tôi dường như không thể tìm thấy nó bằng "Google" –

+1

http://www.phpunit.de/manual/3.6/en/test-doubles.html#test-doubles.stubs – Steve

+5

Lưu ý rằng bạn có thể sử dụng một phương pháp làm gọi lại bằng cách truyền mảng, ví dụ '$ this-> returnCallback (mảng ('MyClassTest', 'myCallback'))'. –

0

Bạn có ý nghĩa như thế này không?

public function TestSomeCondition($condition){ 
    $mockObj = $this->getMockObject(); 
    $mockObj->setReturnValue('yourMethod',$condition); 
} 
+0

Tôi nghĩ rằng là mã SimpleTest, không PHPUnit. Nhưng không, đó không phải là điều tôi muốn đạt được. Giả sử tôi có một đối tượng giả lập trả lại một từ cho một số đã cho. Phương pháp giả của tôi sẽ cần trả lại "một" khi được gọi với 1, "hai" khi được gọi với 2, v.v. $ –

0

Tôi gặp vấn đề tương tự mà tôi không thể làm việc tốt (có ít thông tin đáng ngạc nhiên về PHPUnit). Trong trường hợp của tôi, tôi chỉ thực hiện từng bài kiểm tra riêng biệt kiểm tra - đầu vào được biết đến và đầu ra được biết đến. Tôi nhận ra rằng tôi không cần tạo ra một đối tượng giả lập, tôi chỉ cần một đối tượng cụ thể cho một thử nghiệm cụ thể và do đó tôi tách các thử nghiệm ra và có thể kiểm tra các khía cạnh riêng lẻ của mã của tôi như một đơn vị. Tôi không chắc chắn nếu điều này có thể được áp dụng cho bạn hay không, nhưng đó là xuống đến những gì bạn cần phải kiểm tra.

+0

Thật không may là nó sẽ không hoạt động trong tình huống của tôi. Giả định này được chuyển vào một phương thức mà tôi đang thử nghiệm, và phương thức thử nghiệm gọi phương thức giả lập với các đối số khác nhau. Thật thú vị khi biết rằng bạn không thể giải quyết được vấn đề. Có vẻ như đây có thể là giới hạn PHPUnit. –

-2

Hãy thử:

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value')); 
+0

Câu trả lời này không áp dụng cho câu hỏi ban đầu, nhưng nó chi tiết một vấn đề tương tự như tôi đã có: xác minh rằng một _set_ nhất định các tham số được cung cấp. PHPUnit's với() chấp nhận nhiều đối số, một đối sánh cho mỗi tham số. – TaZ

42

Tôi đã có một vấn đề tương tự (mặc dù hơi khác nhau ... Tôi không cần giá trị trả về khác nhau dựa trên lý lẽ, nhưng phải kiểm tra để đảm bảo 2 bộ tranh luận đã được thông qua cùng chức năng). Tôi stumbled khi sử dụng một cái gì đó như thế này:

$mock = $this->getMock(); 
$mock->expects($this->at(0)) 
    ->method('foo') 
    ->with(...) 
    ->will($this->returnValue(...)); 

$mock->expects($this->at(1)) 
    ->method('foo') 
    ->with(...) 
    ->will($this->returnValue(...)); 

Đó không phải là hoàn hảo, vì nó đòi hỏi rằng thứ tự của 2 cuộc gọi đến foo() được biết đến, nhưng trên thực tế điều này có lẽ không phải là quá xấu.

26

Bạn có lẽ sẽ muốn làm một callback theo kiểu OOP:

<?php 
class StubTest extends PHPUnit_Framework_TestCase 
{ 
    public function testReturnAction() 
    { 
     $object = $this->getMock('class_name', array('method_to_mock')); 
     $object->expects($this->any()) 
      ->method('method_to_mock') 
      ->will($this->returnCallback(array($this, 'returnCallback')); 

     $object->returnAction('param1'); 
     // assert what param1 should return here 

     $object->returnAction('param2'); 
     // assert what param2 should return here 
    } 

    public function returnCallback() 
    { 
     $args = func_get_args(); 

     // process $args[0] here and return the data you want to mock 
     return 'The parameter was ' . $args[0]; 
    } 
} 
?> 
82

Từ các tài liệu phpUnit mới nhất: "Thỉnh thoảng một phương pháp stubbed nên trả lại giá trị khác nhau tùy thuộc vào một danh sách được xác định trước các đối số Bạn có thể sử dụng. returnValueMap() để tạo bản đồ liên kết đối số với các giá trị trả lại tương ứng. "

$mock->expects($this->any()) 
    ->method('getConfigValue') 
    ->will(
     $this->returnValueMap(
      array(
       array('firstparam', 'secondparam', 'retval'), 
       array('modes', 'foo', array('Array', 'of', 'modes')) 
      ) 
     ) 
    ); 
+9

Đây là câu trả lời đúng – NDM

+3

Liên kết trong bài đăng cũ, đúng là có ở đây: [returnValueMap()] (https://phpunit.de/manual/current/en/test-doubles.html#test-doubles.stubs .examples.StubTest5.php) – hejdav

2

Bạn cũng có thể trả lại lập luận như sau:

$stub = $this->getMock(
    'SomeClass', array('doSomething') 
); 

$stub->expects($this->any()) 
    ->method('doSomething') 
    ->will($this->returnArgument(0)); 

Như bạn có thể nhìn thấy trong Mocking documentation, phương pháp returnValue($index) cho phép trả lại đối số nhất định.

9

Nó không phải là chính xác những gì bạn hỏi, nhưng trong một số trường hợp nó có thể giúp:

$mock->expects($this->any())) 
->method('methodToMock') 
->will($this->onConsecutiveCalls('one', 'two')); 

onConsecutiveCalls - trả về một danh sách các giá trị theo thứ tự quy định

1

đèo hai mảng cấp, trong đó mỗi yếu tố là một mảng của:

  • trước tiên là thông số phương pháp và ít nhất là giá trị trả về.

dụ:

->willReturnMap([ 
    ['firstArg', 'secondArg', 'returnValue'] 
]) 
-1
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business'); 

    public function testBusiness() 
    { 
     /* 
      onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called . 
     */ 
     $this->BusinessMock ->method('getEmployees') 
           ->will($this->onConsecutiveCalls(
              $this->returnArgument(0), 
              $this->returnValue('employee')          
              ) 
            ); 
     // first call 

     $this->assertInstanceOf(//$this->returnArgument(0), 
       'argument', 
       $this->BusinessMock->getEmployees() 
       ); 
     // second call 


     $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
     //$this->returnValue('employee'), 


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