2015-06-08 26 views
2

我正在用symfony2進行一些PHPUnit測試。我遇到了一個特定測試的問題。PhpUnit測試存根方法多重返回

我正在測試一個響應表單,當然我的一個類的響應是真實的一個錯誤。我有一個模擬我的數據庫,我有一個從我的databaseRepository的方法之一存根。

問題是,在一個測試中,我做了一個存根到一個有效數組的方法,第二個測試我只想查詢是無效的null。

我的分貝模擬:

//Setting up mock of database repository class 
    $this->db = $this->getMockBuilder('DatabaseRepository') 
     ->disableOriginalConstructor() 
     ->getMock(); 

    $this->db->expects($this->any()) 
     ->method('getRecord') 
     ->will($this->returnValue(self::$registrationRecord)); 

    $this->db->expects($this->any()) 
     ->method('getRecord') 
     ->willReturn(null); 

所以我想有兩個不同的預期,但這obviousley不行.....是有可能有一個存根方法有兩種不同的回報.. ?

測試1:

<?php 


class UnsubscribeRegistrationTemplateTest extends \PHPUnit_Framework_TestCase 
{ 

    /** 
    * @var UnsubscribeRegistrationTemplate 
    */ 
    protected $object; 

    /** 
    * @var ValidationClass 
    */ 
    public $validate; 

    /** 
    * @var DatabaseRepository 
    */ 
    public $db; 

    //Database Record Mock 
    public static $registrationRecord = array 
    (
     'rowid' => '96', 
     'unsubscription' => 'N', 
     'updated' => 'BB' 
    ); 

    /** 
    * 
    */ 
    protected function setUp() 
    { 
     //Setting up mock of validation class 
     $this->validate = $this->getMockBuilder('ValidationClass') 
      ->disableOriginalConstructor() 
      ->getMock(); 

     $this->validate->expects($this->any()) 
      ->method('validateInput') 
      ->willReturn(true); 

     //Setting up mock of database repository class 
     $this->db = $this->getMockBuilder('DatabaseRepository') 
      ->disableOriginalConstructor() 
      ->getMock(); 

     $this->db->expects($this->any()) 
      ->method('getRegistrationRecord') 
      ->will($this->returnValue(self::$registrationRecord)); 

     $this->db->expects($this->any()) 
      ->method('getRegistrationRecord') 
      ->will($this->returnValue(null)); 

     $this->db->expects($this->any()) 
      ->method('setPreRegistrationEnquiryUnsubscriptionEnabled') 
      ->willReturn(true); 

     $this->object = $this->createUnsubscribeRegistrationTemplateInstance(); 
    } 

    /** 
    * @return UnsubscribeRegistrationTemplate 
    * 
    */ 
    public function createUnsubscribeRegistrationTemplateInstance() 
    { 
     //initialize Unsubscribe Registration Template 
     return new UnsubscribeRegistrationTemplate 
     (
      $this->validate, 
      $this->db 
     ); 
    } 

    /** 
    * @param array $mapping 
    * @return Request 
    */ 
    public function createRequest(array $mapping) 
    { 
     $request = new Request(); 

     foreach ($mapping as $k =>$v) 
     { 
      $request->query->set($k, $v); 
     } 

     return $request; 
    } 

    /** 
    * 
    */ 
    public function testUnsubscribeRegistrationTemplateValidResponse() 
    { 
     $request = $this->createRequest(array(
      'registration_id' => '96', 
      'source_channel' => 'BB' 
     )); 

     $response = new Response(
      true, 
      'Unsubscription successful' 
     ); 

     $this->assertEquals($response, $this->object->create($request)); 
    } 

    /** 
    * 
    */ 
    public function testUnsubscribeRegistrationTemplateEmptyResponse() 
    { 
     $request = $this->createRequest(array(
      'registration_id' => '96', 
      'source_channel' => 'BB' 
     )); 

     $response = new Response(
      false, 
      'Registration Record Not Found.' 
     ); 

     $this->assertEquals($response, $this->object->create($request)); 
    } 

    /** 
    * 
    */ 
    public function testIsAlreadyRegisteredValidResponse() 
    { 
     //Testing record is already unsubscribed 
     $registrationRecord = array(
      'unsubscription_enabled' => 'Y' 
     ); 

     $this->assertTrue($this->object->isAlreadyUnsubscribed($registrationRecord)); 
    } 

    /** 
    * 
    */ 
    public function testIsAlreadyRegisteredInValidResponse() 
    { 
     //Testing record not unsubscribed 
     $registrationRecord = array(
      'unsubscription_enabled' => 'N' 
     ); 
     $this->assertFalse($this->object->isAlreadyUnsubscribed($registrationRecord)); 
    } 

    /** 
    * 
    */ 
    protected function tearDown() 
    { 
     unset($this->object); 
    } 

} 
+0

移動在相對測試方法的期望,因爲例如,如果'testIsAlreadyRegisteredInValidResponse'想要那個'getRecord '返回null,將代碼移到那裏,並從設置中移除其他期望。 – Matteo

+0

是的我之前這樣做,但預期的功能被我的PhpStorm突出顯示,我雖然它不會工作,所以從來沒有連續嘗試:/現在我做了,它工作完美,但PHP風暴hihglights它說:方法期望未找到在類庫databaseRepository – Koper

+0

不用擔心它,只是因爲phpstorm不會拒絕正確的對象類型,可能是由於錯誤或缺少PHPDoc註釋。所以你解決了? – Matteo

回答

2

您可以在許多方面做到這一點。
以下兩種方式可能適合您的需求。

1 - 移動getRecord()預計測試

/** 
* @test 
*/ 
public function ifTrue() 
{ 
    $this->db->expects($this->once()) 
    ->method('getRecord') 
    ->will($this->returnValue(self::$registrationRecord)); 

    $request = $this->createRequest(array(
     'id' => '10', 
     'code' => 'BB' 
    )); 

    $response = new Response(
     true, 
     'successful' 
    ); 

    $this->assertEquals($response, $this->object->create($request)); 
} 

/** 
* @test 
*/ 
public function ifFalse() 
{ 
    $this->db->expects($this->once()) 
    ->method('getRecord') 
    ->willReturn(null); 

    $request = $this->createRequest(array(
     'id' => '10', 
     'code' => 'BB' 
    )); 

    $response = new Response(
     false, 
     'Record Not Found.' 
    ); 

    $this->assertEquals($response, $this->object->create($request)); 
} 

正如你可以看到,有很多重複的,所以我們使用dataprovider

2 - 使用@dataProvider

protected function getDataForTest() 
{ 
    return array(
     array(self::$registrationRecord, true, 'successful'), 
     array(null, false, 'Record Not Found.') 
    ); 
} 

/** 
* @dataProvider getDataForTest 
* @test 
*/ 
public function ifTrue($getRecordValue, $bool, $message) 
{ 
    $this->db->expects($this->once()) 
    ->method('getRecord') 
    ->will($this->returnValue($getRecordValue); 

    $request = $this->createRequest(array(
     'id' => '10', 
     'code' => 'BB' 
    )); 

    $response = new Response(
     $bool, 
     $message 
    ); 

    $this->assertEquals($response, $this->object->create($request)); 
} 

使用@dataProvider只要你想測試所有情況下,你可以使用盡可能多的價值。

+0

嗨thx爲你的答案'我試過第一種方式,但它然後說:期望沒有在類 – Koper

+0

找到你在哪裏和什麼時候你的dbMock instanciate? –

+0

以上檢查我已編輯我的問題thx – Koper

2

我想你應該使用PHPUnit at()方法來檢查特定索引處的方法調用。所以你必須用正確的索引來調用expects值參數。

所以,你可以使用下面的代碼:

//Setting up mock of database repository class 
$this->db = $this->getMockBuilder('DatabaseRepository') 
    ->disableOriginalConstructor() 
    ->getMock(); 

$this->db->expects($this->at(0)) // Mock the first call 
    ->method('getRecord') 
    ->will($this->returnValue(self::$registrationRecord)); 

$this->db->expects($this->at(1)) // Mock the second call 
    ->method('getRecord') 
    ->willReturn(null); 

http://www.andrejfarkas.com/2012/07/phpunit-at-method-to-check-method-invocation-at-certain-index/

希望這有助於

+0

嘿thx爲您的重播。我真的嘗試過這種解決方案propably應該提到,但它沒有工作,我有這樣的消息:d>在序列索引0時調用。 索引0期望的調用從未達到。 – Koper

+0

斷言說在你的測試中該方法從未執行過 – Matteo

+0

@Koper你能發佈整個測試課嗎? – Matteo