Wykonywanie testów jednostkowych z zagnieżdżonymi zależnościami i klasami fabryki

Jestem nowym użytkownikiem testów jednostkowych i PHPUnit, ale ostatnio dużo czytałem o wzorcach projektowych i izolowanych testach i zdecydowałem się na refaktoryzację aplikacji, nad którą pracuję, aby pozbyć się klas statycznych, singletonów, zakodowanych zależności i cokolwiek innego zdefiniowanego w zakresie globalnym, miejmy nadzieję, że sprawi, że będzie „testowalny”, a nie ból w dupie w przyszłości, ponieważ ma to być projekt długoterminowy.

Do tej pory uważam, że rozumiem teorię stojącą za testowaniem jednostkowym, ale zastanawiałem się, w scenariuszu, w którym jeden delegat obsługuje zagnieżdżone zależności obiektów do fabryki, jak należy przejść do testowania jednostkowego wspomnianej fabryki lub czy jest to po prostu zbędne, aby ją przetestować ? A jakie jest najlepsze podejście do sprawdzenia, czy „łańcuch” zależności działa dobrze zsynchronizowany?

Pozwólcie, że zilustruję pytania. Załóżmy, że masz następujący kod „starszego”:

<code>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();
</code>

Jest to (o ile rozumiem) złe dla testów jednostkowych, więc zastępujemy zakodowane zależności DI + klasą Factory:

<code>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();
</code>

Teraz (i znowu, o ile rozumiem) House, Door i Knob mogą być testowane jednostkowo z wyśmiewanymi zależnościami. Ale:

1) Co dzieje się teraz z HouseFactory?

Czy powinienem tylko:

Nie testuj go, ponieważ nie ma jeszcze żadnej logiki aplikacji, którą warto przetestować, a fabryki na ogół tak pozostają. Załóżmy, że jeśli testy niezależne dla House, Door i Knob przejdą przez fabrykę, powinno być dobrze.Zmień fabrykę w jakiś sposób, tzn. Użyj funkcji w klasie, aby uzyskać każdą instancję w taki sposób, że można nadpisać te funkcje za pomocą PHPUnit, aby zwracać fałszywe obiekty, na wypadek, gdyby w klasie była jakaś dodatkowa logika, która mogłaby wykorzystać pewne testy w przyszłość.

2) Czy możliwe jest skonfigurowanie testów, które polegają na kilku (nie wyśmiewanych) zależnościach jednocześnie? Rozumiem, że technicznie nie jest to testowanie jednostkowe (być może testowanie integracji?), Ale myślę, że nadal jest doskonale możliwe do wykonania przy użyciu PHPUnit? Biorąc pod uwagę powyższy przykład, chciałbym móc przeprowadzić test, który nie tylko testuje House, Door, Knob i HouseFactory w izolacji, ale także wyniki interakcji rzeczywistych obiektów ze sobą, być może z niektórymi z nich szydzone funkcje, takie jak te, które dotyczą danych. Czy PHPUnit to zły wybór dla tego rodzaju testów?

Z góry dziękuję za poświęcony czas. Zdaję sobie sprawę, że niektóre założenia, które podejmuję, mogą nie być poprawne, ponieważ oczywiście nie jestem ekspertem w tej dziedzinie; korekty są mile widziane i doceniane.

questionAnswers(2)

yourAnswerToTheQuestion