2013-08-28 20 views
0

我有一個名爲「QueryService」的類。在這個類中,有一個名爲「GetErrorCode」的函數。在這個類上也有一個叫做「DoQuery」的函數。所以,你可以放心地說,我有這樣的事情:PHPUnit:如何模擬一個類的功能?

class QueryService { 
    function DoQuery($request) { 
     $svc = new IntegratedService(); 
     $result = $svc->getResult($request); 
     if ($result->success == false) 
      $result->error = $this->GetErrorCode($result->errorCode); 
    } 

    function GetErrorCode($errorCode) { 
     // do stuff 
    } 
} 

我想創建一個PHPUnit的測試,它將測試「DoQuery」。但是,我希望「GetErrorCode」的結果由模擬確定。換句話說,我想說,如果$ errorCode = 1,GetErrorCode必須繞過此函數中的任何邏輯,並返回單詞「ONE」。如果它是除1之外的任何數字,它必須返回「否」。

如何使用PHPUNIT Mocks設置它?

回答

4

要測試此課程,您可以模擬IntegratedService。然後,可以將IntegratedService::getResult()設置爲在模擬中返回您喜歡的任何內容。

然後測試變得更容易。您還需要能夠使用依賴注入來傳遞模擬服務,而不是真正的服務。

類:

class QueryService { 
    private $svc; 

    // Constructor Injection, pass the IntegratedService object here 
    public function __construct($Service = NULL) 
    { 
     if(! is_null($Service)) 
     { 
      if($Service instanceof IntegratedService) 
      { 
       $this->SetIntegratedService($Service); 
      } 
     } 
    } 

    function SetIntegratedService(IntegratedService $Service) 
    { 
     $this->svc = $Service 
    } 

    function DoQuery($request) { 
     $svc = $this->svc; 
     $result = $svc->getResult($request); 
     if ($result->success == false) 
      $result->error = $this->GetErrorCode($result->errorCode); 
    } 

    function GetErrorCode($errorCode) { 
     // do stuff 
    } 
} 

測試:

class QueryServiceTest extends PHPUnit_Framework_TestCase 
{ 
    // Simple test for GetErrorCode to work Properly 
    public function testGetErrorCode() 
    { 
     $TestClass = new QueryService(); 
     $this->assertEquals('One', $TestClass->GetErrorCode(1)); 
     $this->assertEquals('Two', $TestClass->GetErrorCode(2)); 
    } 

    // Could also use dataProvider to send different returnValues, and then check with Asserts. 
    public function testDoQuery() 
    { 
     // Create a mock for the IntegratedService class, 
     // only mock the getResult() method. 
     $MockService = $this->getMock('IntegratedService', array('getResult')); 

     // Set up the expectation for the getResult() method 
     $MockService->expects($this->any()) 
        ->method('getResult') 
        ->will($this->returnValue(1)); 

     // Create Test Object - Pass our Mock as the service 
     $TestClass = new QueryService($MockService); 
     // Or 
     // $TestClass = new QueryService(); 
     // $TestClass->SetIntegratedServices($MockService); 

     // Test DoQuery 
     $QueryString = 'Some String since we did not specify it to the Mock'; // Could be checked with the Mock functions 
     $this->assertEquals('One', $TestClass->DoQuery($QueryString)); 
    } 
} 
+0

+1依賴注入尖 – Cyprian

0

您需要使用PHPUnit創建你的主題下測試通過。如果你告訴PHPUnit你想嘲笑它的模擬方法只有這些方法和其他的類方法將保持原來的類。

所以一個例子測試看起來是這樣的:

public function testDoQuery() 
{ 
    $queryService = $this->getMock('\QueryService', array('GetErrorCode')); // this will mock only "GetErrorCode" method 

    $queryService->expects($this->once()) 
     ->method('GetErrorCode') 
     ->with($this->equalTo($expectedErrorCode)); 
} 

不管怎麼說,正如上面的回答說,你也應該爲了讓儘可能使用Dependency Injection模式模擬IntegratedService以及(因爲根據你上面的例子需要知道$result->success的值)。

所以正確的測試應該是這樣的:

public function testDoQuery_Error() 
{ 
    $integratedService = $this->getMock('\IntegratedService', array('getResult')); 

    $expectedResult = new \Result; 
    $expectedResult->success = false; 

    $integratedService->expects($this->any()) 
     ->method('getResult') 
     ->will($this->returnValue($expectedResult)); 

    $queryService = $this->getMockBuilder('\QueryService') 
     ->setMethods(array('GetErrorCode')) 
     ->setConstructorArgs(array($integratedService)) 
     ->getMock(); 

    $queryService->expects($this->once()) 
     ->method('GetErrorCode') 
     ->with($this->equalTo($expectedErrorCode)) 
     ->will($this->returnValue('expected error msg'); 

    $this->assertEquals($expectedResult->error, 'expected error msg'); 
} 

public function testDoQuery_Success() 
{ 
    $integratedService = $this->getMock('\IntegratedService', array('getResult')); 

    $expectedResult = new \Result; 
    $expectedResult->success = true; 

    $integratedService->expects($this->any()) 
     ->method('getResult') 
     ->will($this->returnValue($expectedResult)); 

    $queryService = $this->getMockBuilder('\QueryService') 
     ->setMethods(array('GetErrorCode')) 
     ->setConstructorArgs(array($integratedService)) 
     ->getMock(); 

    $queryService->expects($this->never()) 
     ->method('GetErrorCode'); 
}