Это упрощенная версия кода, с которым я работаю:
class FirstClass{
public $theSecondObject;
function exampleForTesting(){
$this->theSecondObject = SecondClass::getInstance();
return $this->theSecondObject->getRandomSentence();
}
}
class SecondClass{
private static $instance = null;
private $randomSentence;
private function __construct($someString){
$this->randomSentence = $someString;
}
public static function getInstance(){
if(self::instance === null){
self::$instance = new SecondClass('Just a random sentence.');
}
return self::$instance;
}
public function getRandomSentence(){
return $this->randomSentence;
}
}
class FirstClassTestCase {
public function startTest($method){
$this->firstClassObject = new FirstClass();
}
public function testExampleForTesting(){
$this->firstClassObject->theSecondObject = $this->getMock('SecondClass', ['getRandomSentence']);
$this->firstClassObject->theSecondObject->expects($this->any()
->method('getRandomSentence')
->will($this->returnValue('A test unexpected sentence.'));
$expected = 'Just a random sentence.';
$actual = $this->firstClassObject->exampleForTesting();
$this->assertNotEquals($expected, $actual);
}
}
У меня есть FirstClass с функцией exampleForTesting (), которая делает вызов функции SecondClass (), возвращаемое значение которой я хотел бы смоделировать для тестирования. Однако конструктор SecondClass () является закрытым, и в результате выполнения теста в результате выдается ошибка:
Fatal Error Error: Call to private SecondClass::__construct()
Похоже, это связано с уникальным способом создания экземпляров объектов SecondClass с помощью функции getInstance (). Есть ли потенциальный способ обойти эту проблему, не меняя конструктор SecondClass? Второй класс на самом деле является внешним вызовом в моем приложении, поэтому я не могу его изменить.
Кроме того, я заметил, что даже когда я пытался установить конструктор в public, чтобы посмотреть, пройдет ли тест, он на самом деле не пройдёт, так как переменная $ actual генерирует то же значение, что и ожидаемый $. Я неправильно выполняю макет возвращаемого значения?
Одним из вариантов будет изменение вашей реализации и работа с чем-то под названием внедрение зависимости.
class FirstClass
{
public function __construct(SecondClass $secondClass)
{
//...
}
}
Таким образом, вы могли бы высмеять SecondClass
легко в вашем тесте и передать его в качестве параметра FirstClass
,
class FirstClassTest {
public function testExampleForTesting()
{
$mock = Mockery::mock(SecondClass::class);
$mock->shouldReceive('getRandomSentence')
->andReturn('A test sentence.');
$firstClassObject = new FirstClass($mock);
// ...
}
}
Иногда также имеет смысл обернуть класс, который вам не принадлежит, поскольку это часто дает вам еще большую гибкость.
Других решений пока нет …