我有一个名为“QueryService”的类。在这个类上,有一个名为“GetErrorCode”的函数。此类上还有一个名为“DoQuery”的函数。所以你可以肯定地说我有这样的事情:
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
}
}
我想创建一个测试“DoQuery”的phpunit测试。但是,我希望模拟确定“GetErrorCode”的结果。换句话说,我想说如果$ errorCode = 1,GetErrorCode必须绕过此函数中的任何逻辑,并返回单词“ONE”。如果是1以外的任何数字,则必须返回“NO”。
如何使用PHPUNIT Mocks进行设置?
答案 0 :(得分: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));
}
}
答案 1 :(得分: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');
}