2017-01-22 12 views
1

我有这2类:我如何(单位)基于静态方法调用测试类行为?

AbstractTaskDispatcher

<?php 

declare(strict_types=1); 

namespace MyExample; 

abstract class AbstractTaskDispatcher 
{ 
    public final function getResult(Task $task) : Result 
    { 
     if($worker = $this->getWorker($task)) 
      return $worker->getResult(); 
     else 
      return Result::getUnprocessableTaskResult(); 
    } 

    abstract protected function getWorker(Task $task) : Worker; 
} 

?> 

结果

<?php 

declare(strict_types=1); 

namespace MyExample; 

class Result 
{ 
    private $code; 

    public function __construct(int $code = 0) 
    { 
     $this->code = $code; 
    } 

    public static function getUnprocessableTaskResult() : Result 
    { 
     return new Result(1000); 
    } 

    public function getCode() : int 
    { 
     return $this->code; 
    } 
} 

?> 

我想写PHPUnit的单元测试得到肯定AbstractTaskDispatcher ::的getResult( )如果找不到合适的Worker来处理任务,则返回Result :: getUnprocessableTaskResult()。

我不想这样做:

  1. 安排:$ expectedResult =结果:: getUnprocessableTaskResult();操作:$ result = $ dispatcherStub-> getResult(New Task());
  2. 断言:assertEquals($ result,$ expectedResult);

因为它依赖于Result类的实现并且不会成为单元测试。

我试图做一些事情:

<?php 

    use PHPUnit\Framework\TestCase; 
    use MyExample as ex; 

    class AbstractDispatcherTest extends TestCase 
    { 
     public function test_getResultSouldReturnUnprocessableTaskResultIfNoWorkerFound() 
     { 
      $dispatcher = $this->getMockForAbstractClass(ex\AbstractDispatcher::class); 
      $arbitraryCode = 6666; 
      $expectedResult = new ex\Result($arbitraryCode); 
      $resultClass = $this->getMockClass('Result', ['getUnprocessableTaskResult']); 
      $resultClass::staticExpects($this->any()) 
       ->method('getUnprocessableTaskResult') 
       ->will($this->returnValue($expectedResult)); 

      $result = $dispatcher->getResult(new ex\Task([])); 

      $this->assertEquals($expectedResult, $result); 
     } 
    } 

?> 

但staticExpects()方法被废弃,在当前的PHPUnit版本中不再存在。

我该如何写这个测试?

+0

@berty嗨,只有一个问题:如何才能返回'FALSE'方法'getWorker'?严格的类型定义不能接受你向'Worker'对象实例返回不同的东西 – Matteo

+0

从设计的角度来看,你为什么选择使用静态方法来返回?没有任何理由认为''AbstractTaskDispatcher'不能仅仅返回一个新的'Result'实例,因为它知道Result类开始于何处。 –

+0

嗨@Matteo,我用PHP 7.1编写了它,并且记住了可空类型的返回类型,即使我目前在PHP 7.0上 – berty

回答

0

您可以简单地测试如下:

public function test_getResultSouldReturnUnprocessableTaskResultIfNoWorkerFound() 
{ 
    $dispatcher = $this->getMockForAbstractClass(ex\AbstractTaskDispatcher::class); 
    $dispatcher->expects($this->once()) 
     ->method('getWorker') 
     ->willReturn(false); 

    $result = $dispatcher->getResult(new ex\Task([])); 

    // Unuseful: this is implicit by the method signature 
    $this->assertInstanceOf(ex\Result::class, $result); 
    $this->assertEquals(1000, $result->getCode()); 
} 

NB:我改变CLASSE AbstractTaskDispatcher的方法定义如下,以返回false值:

/** 
* @param Task $task 
* @return Result|false The Result of the task or false if no suitable Worker is found to process the Task 
*/ 
abstract protected function getWorker(Task $task); 

编辑:

正如您所评论的,您不能检查以下代码而不是硬编码结果代码:

$this->assertEquals(ex\Result::getUnprocessableTaskResult(), $result); 
    // Or 
    $this->assertEquals(ex\Result::getUnprocessableTaskResult()->getCode(), $result->getCode()); 

希望这有助于

+0

这是我不想做的事情,因为它依赖于Result类,它不在测试范围之内。通过更改Result类代码,我可以使此测试失败或成功。例如,即使AbstractDispatcher :: getResult()被破坏,我也可以通过在Result :: getCode()中的硬代码中返回1000来通过测试。所以这不是严格的*单元测试。否则,如果我选择接受测试的“非统一”,我认为我最好在测试中'assertEquals(ex \ Result :: getUnprocessableTaskResult(),$ result)'以避免写入“1000” 。 – berty

相关问题