2

モデルの単体テストを適切に記述できるように、モデルをリファクタリングしたいと思います。しかし、私にはいくつかの依存関係があります。誰かが私にこれらの依存関係を取り除く方法を正しい方向に向けることができますか?

class Customer
{
    public function save(array $data, $id = NULL)
    {
        // create or update
        if (empty($id)) {
            $customer = new \Entities\Customer();
        } else {
            $customer = $this->findById((int) $id);
        }

        $birthday = new DateTime();
        list($day, $month, $year) = explode("/", $data['birthday']);
        $birthday->setDate($year, $month, $day);

        $customer->setFirstName($data['firstName']);
        $customer->setLastName($data['lastName']);
        $customer->setCompany($data['company']);
        $languageModel = new Application_Model_Language();
        $customer->setLanguage($languageModel->findById($data['language']));
        $resellerShopModel = new Application_Model_ResellerShop();
        $customer->setResellerShop($resellerShopModel->findById($data['resellerShop']));
        $customer->setEmail($data['email']);
        $customer->setPhone($data['phone']);
        $customer->setGender($data['gender']);
        $customer->setBirthday($birthday);
        $customer->setType($data['type']);
        $customerSectorModel = new Application_Model_CustomerSector();
        $customer->setSector($customerSectorModel->findById($data['sector']));
        $customerReferenceModel = new Application_Model_CustomerReference();
        $customer->setReference($customerReferenceModel->findById($data['reference']));
        if (isset($data['password'])) {
            $customer->setPassword($this->_hashPassword($data['password']));
        }

        return $customer;
    }
}
4

2 に答える 2

2

依存関係は、関数本体のコンストラクター呼び出しだと思います。私の考えでは、単体テストでそれらを置き換える方法は3つあります。

  1. すべての異なるクラスが実装されているモックライブラリを作成し、テストを実行するには、実際のモジュールの代わりにモックライブラリを含めます。

  2. 外部クラスのデフォルトパラメータのセットを関数宣言に追加します。最終的に、新しい関数宣言はのようになりますpublic function save(array $data, $id = NULL, $newCustomer=\Entities\Customer(), $newLangModel = Application_Model_Language, ...)。また、関数本体では、変数を使用して、などの実際のオブジェクトを作成します$customer = new $newCustomer()。テストコードでは、すべての依存クラスをモッククラスでオーバーライドできます。

  3. すべてのクラスにパラメータを追加するのではなく、2つのファクトリを作成します。1つは現在のオブジェクトを作成し、もう1つはモックオブジェクトを作成します。関数内では、ファクトリからのみ新しいオブジェクトを要求します。

    このアプローチは、工事を傍受する必要のある場所が多数ある場合に役立ちます。変更する必要のある機能が1つしかない場合、工場は過剰に設計されています。

于 2010-09-29T14:10:34.390 に答える
0

コードを振り返ると、このクラスは\ Entities \ Customerクラスのファクトリとリポジトリの両方として機能しているようです(これは明らかではなかったため、名前の変更をより明確にすることを検討できます)。また、その関数がsaveという名前であることに同意しません。これは、オブジェクトを返すだけで、それを永続化する必要があるためですが、それはよりセマンティクスです。

現在のコードでは、2つの異なるテストが必要であることがわかります。

1)\ Entities\Customerクラスをテストします。

ゲッターとセッターのそれぞれが正しく機能していること、または少なくともその背後にビジネスロジックがあるものが機能していることを確認します。たとえば、ResellerShopを設定した場合、正しい/有効なResellerShowオブジェクトを取得したかどうかを確認してください。多かれ少なかれ、ビジネスロジックをテストする必要があります。基本フィールドの取得/セット(名前など)は、実際には独自のテストを必要としません(100%のコードカバレッジが目標でない限り、そうではないと思います)。

2)(Factory \ Repository)クラスをテストします。

配列に渡されたデータに応じて、表示したクラスが正しく作成(または失敗)することを確認してください。たとえば、必須フィールドが渡されない場合は失敗し、顧客エンティティオブジェクトを返さないようにする必要があります。

関心の分離を目的としています。Entityクラスにはビジネスロジックが含まれている必要があり、オブジェクトインスタンス化コードとは別にテストする必要があります。

于 2010-09-29T20:53:28.327 に答える