Я новичок в модульном тестировании и PHPUnit, но в последнее время я много читаю о шаблонах проектирования и изолированных тестах, и я решил реорганизовать приложение, над которым я работаю, чтобы избавиться от статических классов, синглетов, жестко закодированных зависимостей и всего остального, определенного в глобальном масштабе, надеясь сделать его "проверяемым", а не боли в заднице, чтобы работать в будущем, поскольку он предназначен для долгосрочного проекта.
До сих пор я считаю, что я понимаю теорию модульного тестирования, но мне было интересно, в сценарии, когда один делегат обрабатывает вложенные зависимости объектов к Factory, как следует идти об модульном тестировании, указанном Factory, или это просто лишний, чтобы проверить его? И что лучше всего подходит для проверки того, что "цепочка" зависимостей хорошо работает в синхронизации?
Позвольте мне проиллюстрировать вопросы. Предположим, у вас есть следующий "устаревший" код:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct() {
$this->door = new Door();
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct() {
$this->knob = new Knob();
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
$house = new House();
Это (насколько я понимаю) плохо для модульного тестирования, поэтому мы заменяем закодированные зависимости с помощью DI + a Factory class:
class House {
protected $material;
protected $door;
protected $knob;
public function __construct($door) {
$this->door = $door;
$this->knob = $this->door->getKnob();
$this->material = "stone";
echo "House material: ".$this->material . PHP_EOL . "<br/>";
echo "Door material: ".$this->door->getMaterial() . PHP_EOL . "<br/>";
echo "Knob material: ".$this->knob->getMaterial() . PHP_EOL . "<br/>";
}
}
class Door {
protected $material;
protected $knob;
public function __construct($knob) {
$this->knob = $knob;
$this->material = "wood";
}
public function getKnob() {
return $this->knob;
}
public function getMaterial () {
return $this->material;
}
}
class Knob {
protected $material;
public function __construct() {
$this->material = "metal";
}
public function getMaterial () {
return $this->material;
}
}
class HouseFactory {
public function create() {
$knob = new Knob();
$door = new Door($knob);
$house = new House($door);
return $house;
}
}
$houseFactory = new HouseFactory();
$house = $houseFactory->create();
Теперь (и опять же, насколько я понимаю) House, Door and Knob могут быть проверены с помощью смехотворных зависимостей. Но:
1) Что происходит с HouseFactory сейчас?
Если нужно просто:
- Не тестируйте его, так как он еще не тестировал какую-либо прикладную логику, и на самом деле фабрики остаются такими. Предположим, что если независимые тесты для House, Door и Knob проходят, Factory должен быть в порядке.
- Рефакторируйте Factory каким-то образом, то есть используя функции внутри класса, чтобы получить каждый экземпляр таким образом, чтобы можно было переопределить эти функции через PHPUnit, чтобы возвращать макетные объекты, на всякий случай, если в классе есть какая-то дополнительная логика может использовать некоторые испытания в будущем.
2) Возможно ли настроить тесты, которые полагаются на несколько (не издевающихся) зависимостей сразу? Я понимаю, что это технически не модульное тестирование (возможно, интеграционное тестирование?), Но я думаю, что он все еще отлично справляется с использованием PHPUnit? Учитывая приведенный выше пример, я хотел бы иметь возможность настроить тест, который не только изолирует House, Door, Knob и HouseFactory, но и результаты взаимодействия реальных объектов друг с другом, возможно, с некоторыми из них функции издеваются, например те, которые относятся к данным. Является ли PHPUnit плохим выбором для такого рода тестов?
Заранее благодарим за ваше время. Я понимаю, что некоторые из допущений, которые я делаю, могут быть неверными, поскольку я, очевидно, не специалист по этому вопросу; исправления приветствуются и оцениваются.