Проблема не в заглушке метода, а в вашем классе.
Вы делаете работу в конструкторе. Чтобы установить объект в состояние, вы выбираете удаленный файл. Но этот шаг не обязателен, поскольку объекту не нужны эти данные, чтобы быть в допустимом состоянии Вам не нужен результат из файла, прежде чем вы на самом деле вызовете getFormatted
.
Вы можете отложить загрузку:
class ClassA {
private $dog;
private $formatted;
public function __construct($param1) {
$this->dog = $param1;
}
protected getResultFromRemoteServer() {
if (!$this->formatted) {
$this->formatted = file_get_contents(
'http://whatever.com/index.php?' . $this->dog
);
}
return $this->formatted;
}
public getFormatted() {
return ("The dog is a " . $this->getResultFromRemoteServer());
}
}
так что вы лениво загружаете удаленный доступ, когда он действительно необходим. Теперь вам вообще не нужно заглушать getResultFromRemoteServer
, но вместо этого можно заглушить getFormatted
. Вам также не нужно будет открывать свой API для тестирования и делать общедоступным getResultFromRemoteServer
.
В sidenote, даже если это всего лишь пример, я переписал бы этот класс, чтобы прочитать
class DogFinder
{
protected $lookupUri;
protected $cache = array();
public function __construct($lookupUri)
{
$this->lookupUri = $lookupUri;
}
protected function findById($dog)
{
if (!isset($this->cache[$dog])) {
$this->cache[$dog] = file_get_contents(
urlencode($this->lookupUri . $dog)
);
}
return $this->cache[$id];
}
public function getFormatted($dog, $format = 'This is a %s')
{
return sprintf($format, $this->findById($dog));
}
}
Поскольку это Finder, возможно, имеет смысл сделать публичным findById
сейчас. Просто держите его защищенным, потому что это то, что вы имели в своем примере
Другим вариантом будет расширение Подопытного и замена метода getResultFromRemoteServer
собственной реализацией, возвращающей Poodle
. Это означает, что вы тестируете не фактический ClassA
, а подкласс ClassA
, но это то, что происходит, когда вы все равно используете Mock API.
Начиная с PHP7, вы можете использовать анонимный класс, например:
public function testPoodle() {
$stub = new class('dog52') extends ClassA {
public function getResultFromRemoteServer() {
return 'Poodle';
}
};
$expected = 'This dog is a Poodle';
$actual = $stub->getFormatted();
$this->assertEquals($expected, $actual);
}
До PHP7 вы просто писали обычный класс, расширяющий Subject-Under-Test и использовали его вместо Subject-Under-Test . Или используйте disableOriginalConstructor
, как показано в другом месте на этой странице.