Executando Teste de Unidade com Dependências Aninhadas e Classes de Fábrica

Eu sou novo em testes de unidade e PHPUnit, mas tenho lido muito ultimamente sobre padrões de projeto e testes isolados e decidi refatorar um aplicativo em que estou trabalhando para me livrar de classes estáticas, singletons, dependências codificadas e qualquer outra coisa definida no escopo global, esperançosamente tornando-a "testável" e não uma dor no saco para manter no futuro, uma vez que se destina a ser um projeto de longo prazo.

Até agora eu acredito que eu entendo a teoria por trás do teste unitário, mas eu estava imaginando, em um cenário onde um delegado manipula dependências aninhadas de objetos para uma Factory, como deve ser feito o teste unitário, Factory, ou é apenas redundante testá-lo? ? E qual é a melhor abordagem para testar se a "cadeia" de dependências funciona bem em sincronia?

Deixe-me ilustrar as perguntas. Suponha que você tenha o seguinte código "legado":

<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>

Isso é (até onde meu entendimento é) ruim para testes unitários, então nós substituímos as dependências codificadas por DI + uma classe 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>

Agora (e novamente, tanto quanto eu entendo) House, Door e Knob podem ser testados na unidade com dependências simuladas. Mas:

1) O que acontece com o HouseFactory agora?

Deve um apenas:

Não teste-o, pois ele ainda não tem lógica de aplicativo que valha a pena ser testada e as fábricas geralmente permanecem assim. Suponha que, se os testes independentes para House, Door & Knob passarem, a Factory deve estar bem.Refatorar a fábrica de alguma forma, ou seja, usando funções dentro da classe para obter cada instância de tal forma que um pode substituir essas funções via PHPUnit para retornar objetos de simulação, apenas no caso de haver alguma lógica extra na classe que poderia usar alguns testes em o futuro.

2) É possível configurar testes que dependam de várias dependências (não escarnecidas) de uma só vez? Eu entendo que isso tecnicamente não é teste de unidade (teste de integração, talvez?), Mas eu acho que ainda é perfeitamente factível usando PHPUnit? Dado o exemplo acima, gostaria de ser capaz de configurar um teste que não apenas teste House, Door, Knob e HouseFactory isoladamente, mas também os resultados da interação dos objetos reais uns com os outros, talvez com alguns de seus funções zombadas, como as que lidam com dados. O PHPUnit é uma má escolha para este tipo de testes?

Agradeço antecipadamente pelo seu tempo. Eu percebo que algumas das suposições que estou fazendo podem não estar corretas, já que eu obviamente não sou especialista no assunto; correções são bem-vindas e apreciadas.

questionAnswers(2)

yourAnswerToTheQuestion