2015-01-21 3 views
1

구체적인 메소드가있는 추상 클래스가 있습니다. 그래서 나는 그 구체적인 방법을 시험하고 싶다.phpunit을 사용하여 추상 메소드를 호출하는 구체적인 메소드를 테스트하는 방법

abstract class File { 

    private $debug_filename_pattern = 'DELETE_ME_%s.debug'; 
    private $filename; 
    private $filepath; 

    abstract public function buildFilename(); 

    public function __construct($debug = false) { 
     $filename = $this->buildFilename(); 
     if ($debug) { 
      $filename = sprintf($this->debug_filename_pattern, $filename); 
     } 
     $this->filename = $filename; 
     $this->buildFilepath(); 
    } 

    private function buildFilepath() { 
     $this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename; 
    } 
} 

내가 phpunit documentation에서 추상 클래스 테스트에 절을 읽고 난 그 테스트를 내놓았다 :

여기 내 추상 클래스입니다

final class FileTest extends \PHPUnit_Framework_TestCase { 

    public function test() { 
     $stub = $this->getMockForAbstractClass('MyBundle\File', [true]); 
     $stub->expects($this->atLeastOnce()) 
       ->method('buildFilename') 
       ->withAnyParameters() 
       ->will($this->returnValue('test.log')); 
     $this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath()); 
    } 

} 

그러나 그것은 작동하지 않습니다. 내 어설 항상이 오류 메시지와 함께 실패 반환 : 내 모의 객체 인스턴스화 이해하고 내가 buildFilename 방법에 대한 모의를 추가

Failed asserting that two strings are equal. 
--- Expected 
+++ Actual 
@@ @@ 
-'C:\xampp\tmp\DELETE_ME_test.log.debug' 
+'C:\xampp\tmp\DELETE_ME_.debug' 

. 내 시험을 항상 실패하게 만듭니다.

인스턴스화 전에 내 추상 메소드를 조롱하는 방법이 있습니까? 대신에 필자의 추상 클래스를 리팩터링해야할까요?

+0

이전에는 필요에 따라 테스트 코드에 추상 클래스에 대한 클래스를 만든 다음 해당 클래스의 구체적인 메서드를 테스트합니다. –

+0

문제는 구체적인 방법을 테스트하지 않습니다. 문제는 인스턴스 생성 후 모의 객체가 정의 된 추상 메소드를 호출하는 생성자입니다. 이 메서드는 항상 null을 반환합니다. –

답변

1

나는 당신이 원하는 방식으로 당신의 모의를 설정할 수 있다고 생각하지 않습니다. 구성 메소드는 ->getMock() 일 때 호출됩니다. 그런 다음 사실 이후에 기대를 설정하려고합니다.

일반적으로이 경우와 같이 테스트하기가 어려워지면 설계에 문제가 있음을 알 수 있습니다. 나는 당신이 가진 이슈가이 경우 생성자에서 너무 많이하고 있다고 생각한다.

개체 구성에서 파일 경로를 확인하기 위해 모든 종류의 무거운 작업을 수행하고 있습니다. getFilePath에 전화 할 때 변경되도록하십시오. 클래스는 다음과 같이보고 끝낼 것 : 테스트에서

이제
abstract class File { 

    private $debug_filename_pattern = 'DELETE_ME_%s.debug'; 
    private $filename; 
    private $filepath; 
    protected $debug; 

    abstract public function buildFilename(); 

    public function __construct($debug = false) { 
     $this->debug = $debug; 
    } 

    private function buildFilepath() { 
     $filename = $this->buildFilename(); 
     if ($this->debug) { 
      $filename = sprintf($this->debug_filename_pattern, $filename); 
     } 
     $this->filename = $filename; 
     $this->filepath = ini_get('upload_tmp_dir') . DIRECTORY_SEPARATOR . $this->filename; 
    } 

    public function getFilePath() { 
     if(!this->filepath) { 
      $this->buildFilepath(); 
     } 

     return $this->filepath; 
    } 
} 

경로는 한 번만 당신의 주장을 한 번 더 추가 구축됩니다 있는지 확인.

final class FileTest extends \PHPUnit_Framework_TestCase { 

    public function test() { 
     $stub = $this->getMockForAbstractClass('MyBundle\File', [true]); 
     $stub->expects($this->once()) 
       ->method('buildFilename') 
       ->withAnyParameters() 
       ->will($this->returnValue('test.log')); 
     $this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath()); 
     $this->assertEquals('C:\xampp\tmp\DELETE_ME_test.log.debug', $stub->getFilePath()); 
    } 

} 
+0

은 $ this-> once()이어야합니다. – crowebird

+0

@crowebird 고마워요. 테스트를 수정했습니다. – Schleis

+0

나는 당신이 묘사 한 것과 매우 비슷한 것을 만들었습니다. 통찰력을 가져 주셔서 감사합니다. –

관련 문제