16

私は単体テストと PHPUnit は初めてですが、最近デザイン パターンと分離されたテストについてよく読んでおり、静的クラス、シングルトン、ハードコーディングされた依存関係を取り除くために、現在取り組んでいるアプリケーションをリファクタリングすることにしました。グローバルスコープで定義された他のものはすべて、うまくいけば「テスト可能」になり、長期的なプロジェクトになることを意図しているため、将来的に維持するのに苦労しません。

これまでのところ、単体テストの背後にある理論を理解していると思いますが、オブジェクトのネストされた依存関係の処理を 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 + Factory クラスに置き換えます。

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、および Knob は、モック化された依存関係で問題なく単体テストできます。しかし:

1) HouseFactory はどうなりますか?

必要なのは:

  • テストする価値のあるアプリケーション ロジックがまだないため、テストしないでください。通常、ファクトリはそのままです。House、Door、Knob の独立したテストに合格した場合、Factory は問題ないと仮定します。
  • 何らかの方法でファクトリをリファクタリングします。つまり、クラス内の関数を使用して各インスタンスを取得し、PHPUnit を介してこれらの関数をオーバーライドしてモック オブジェクトを返すようにします。未来。

2) 一度に複数の (モックされていない) 依存関係に依存するテストをセットアップすることは可能ですか? これは技術的に単体テストではないことは理解していますが(おそらく統合テストですか?)、それでもPHPUnitを使用して完全に実行できると思いますか?上記の例を考えると、House、Door、Knob、HouseFactory を個別にテストするだけでなく、実際のオブジェクトの相互の相互作用の結果もテストするテストをセットアップできるようにしたいと考えています。データを扱う関数など、モックされた関数。PHPUnit は、この種のテストには適していませんか?

お時間をいただきありがとうございます。私は明らかにこの問題の専門家ではないので、私が行っているいくつかの仮定が正しくない可能性があることを認識しています。修正は大歓迎です。

4

2 に答える 2

0

継承でテストできます。

テストのために House を FakeHouse で拡張し、$material、$door、$knob などをテスト後に変更したかどうかを確認します。

于 2016-04-23T16:46:59.630 に答える