문제

구현의 일부로 다른 객체를 구성하는 객체의 경우 단위 테스트를 작성하는 가장 좋은 방법은 무엇입니까? 사소한 예 :

class myObj { 
    public function doSomethingWhichIsLogged()
    {
        // ...
        $logger = new logger('/tmp/log.txt');
        $logger->info('some message');
        // ...
    }
}

로거 객체 의존성을 주입하여 단위 테스트에서 조롱 할 수 있도록 객체가 설계 될 수 있다는 것을 알고 있지만 항상 그런 것은 아닙니다. 더 복잡한 시나리오에서는 다른 객체를 구성하거나 정적 방법을 호출해야합니다. .

로거 객체를 테스트하고 싶지 않기 때문에 MyOBJ 만 어떻게 진행합니까? 테스트 스크립트와 함께 스터브 "더블"을 생성합니까? 같은 것 :

class logger
{
    public function __construct($filepath) {}
    public function info($message) {}
}

class TestMyObj extends PHPUnit_Framework_TestCase 
{
    // ...
}

이것은 작은 물체의 경우 가능해 보이지만 SUT가 반환 값에 의존하는 더 복잡한 API의 고통이 될 것입니다. 또한, 동일하게 의존성 객체에 대한 호출을 테스트하려면 어떻게해야합니까? 통과하기보다는 SUT에 의해 인스턴스화되는 물체를 조롱하는 방법이 있습니까?

나는 Mocks에서 Man Page를 읽었지만 집계되지 않고 의존성이 구성되는이 상황을 다루지 않는 것 같습니다. 어떻게 하시나요?

도움이 되었습니까?

해결책

이미 알고있는 것처럼, 구체적인 클래스 종속성은 테스트를 어렵게 만들 수 있습니다 (또는 완전히 불가능). 그 종속성을 분리해야합니다. 기존 API를 깨뜨리지 않는 간단한 변경은 현재 동작에 기본값을 제공하지만이를 무시할 수있는 후크를 제공하는 것입니다. 이를 구현할 수있는 방법에는 여러 가지가 있습니다.

일부 언어에는 모의 클래스를 코드에 주입 할 수있는 도구가 있지만 PHP에 대해서는 이와 같은 것을 모릅니다. 대부분의 경우 어쨌든 코드를 리팩토링하는 것이 좋습니다.

다른 팁

수행원 troelskn 여기에 당신이해야 할 일의 기본 예가 있습니다.

<?php

class MyObj
{
    /**
     * @var LoggerInterface
     */
    protected $_logger;

    public function doSomethingWhichIsLogged()
    {
        // ...
        $this->getLogger()->info('some message');
        // ...
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->_logger = $logger;
    }

    public function getLogger()
    {
        return $this->_logger;
    }
}


class MyObjText extends PHPUnit_Framework_TestCase
{
    /**
     * @var MyObj
     */
    protected $_myObj;

    public function setUp()
    {
        $this->_myObj = new MyObj;
    }

    public function testDoSomethingWhichIsLogged()
    {
        $mockedMethods = array('info');
        $mock = $this->getMock('LoggerInterface', $mockedMethods);
        $mock->expects($this->any())
             ->method('info')
             ->will($this->returnValue(null));

        $this->_myObj->setLogger($mock);

        // do your testing
    }
}

모의 개체에 대한 자세한 내용은 찾을 수 있습니다 매뉴얼에서.

질문을 오해 한 것 같습니다. 다시 시도하겠습니다.

아직 너무 늦지 않은 경우 로거에 싱글 톤 패턴 또는 공장을 사용해야합니다.

class LoggerStub extends Logger {
    public function info() {}
}
Logger::setInstance(new LoggerStub());
...
$logger = Logger::getInstance();

코드를 변경할 수없는 경우 과부하중인 Catch-All 클래스를 사용할 수 있습니다. __전화()

class GenericStub {
    public function __call($functionName, $arguments) {}
}

실제로 PHPUnit을 구축하는 동일한 사람들이 출시 한 PHP 클래스 과부하에 대한 합리적으로 새로운 확장이 있습니다. 코드를 리팩터링 할 수없는 경우 새 연산자를 무시할 수 있습니다. 불행히도 Windows에 설치하는 것은 간단하지 않습니다.

URL입니다 http://github.com/johannes/php-test-helpers/blob/master/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top