phpunit의 종속성을 가진 객체 테스트
-
23-08-2019 - |
문제
구현의 일부로 다른 객체를 구성하는 객체의 경우 단위 테스트를 작성하는 가장 좋은 방법은 무엇입니까? 사소한 예 :
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/