0

いくつかの単体テストをレガシー PHP アプリケーションに実装しようとしています。

これには多くの課題がありましたが、特にこの質問については、現在、アプリの構成を管理する小さなクラスを検討しています。

クラス インターフェイスは非常に単純です。次のことを行います。

  • コンストラクターは Populate メソッドを呼び出します。このメソッドは Recordset クラスを使用して、要求されたモジュールの構成をデータベースから読み込みます。
  • 指定された構成値を返す Get メソッド。
  • 設定値をメモリに設定する Set メソッド。
  • 構成の更新を DB に書き戻す Save メソッド。

Get/Set メソッドのテストは簡単です。それらはプライベート配列に直接マップされ、期待どおりに機能します。

私が抱えている問題は、データベース処理のテストにあります。このクラスは、構成テーブルのいくつかのフィールド (モジュール名、言語など) を使用して、ロードする構成項目と優先度を決定します。そのために、一連の精巧な SQL 文字列を作成し、DB を直接呼び出して正しい構成データを取得します。

このための単体テストを作成する方法がわかりません。Get/Set メソッドを除けば、このクラスはほぼ完全に SQL 文字列の作成と実行で構成されています。

実際のDBに対して実際に実行せずに賢明にテストする方法と、それに伴うすべての問題がわかりません-他に何もないとしても、構成ローダーの複雑さは、少なくとも7つまたはわずかに異なる構成で入力された 8 つのテスト データベース。それは手に負えず壊れやすいように思えます。

ここからどのように進めればよいか、誰かが提案できますか? この種のクラスを単体テストすることさえ可能ですか?

どうもありがとう。

4

2 に答える 2

1

ここでデータベースにアクセスしないと、単体テストがいくらか無意味になることに同意するかどうかはわかりません。私の目標は、データベースを使用せずに、テスト対象の SQL を生成するビジネス ロジックを取得することです。これが私が話していることの例です:

class Foo {

    // ... Getters and setters for your config ...

    public function doSomeBusinessLogicThenHitDb()
    {
        $sql = 'SELECT * FROM mytable WHERE ';
        $sql .= $this->_doSomethingComplicatedThatInvolvesParsingTheConfig();
        $this->_queryDb($sql);
    }

    protected function _queryDb($sql)
    {
        // Do something with a PDO or whatever
    }
}

ビットを別の関数に抽象化し_queryDb()たら、次のテストを記述できます。

    public function testMyClassUnderSomeCircumstances()
    {
        // Set up config
        $exampleConfig = // whatever

        // Set up expected result
        $whatTheSqlShouldLookLikeForThisConfig = 'SELECT ... WHERE ...';

        // Set up a partial mock that doesn't actually hit the DB
        $myPartialMockObject = $this->getMock('Foo', array('_queryDb'), array(), '');
        $myPartialMockObject->expects($this->once())
                            ->method('_queryDb')
                            ->with($whatTheSqlShouldLookLikeForThisConfig);

        // Exercise the class under test
        $myPartialMockObject->setConfig($exampleConfig);
        $myPartialMockObject->doSomeBusinessLogicThenHitTheDb();
    }

このテストのポイントは、SQL を生成するビジネス ロジックをテストすることであり、データベース自体をテストすることではありません。結果の SQL は本来あるべき姿のようにならなければならないという期待を設定することで、無害なリファクタリング_doSomethingComplicatedThatInvolvesParsingTheConfig()によってコードが誤って壊れた場合に、以前とは異なる SQL を生成することで、テストが確実に失敗するようにします。

データベースを含むアプリケーション全体をテストすることが目標である場合は、Selenium などの適切な統合テスト スイートを試してください。単体テストは個々のクラスを監視し、想定どおりに動作しなくなったときに通知します。オーバーリーチを許すと、実行速度とエラーのローカリゼーションの問題に直面します (つまり、テスト対象のクラスはもちろん、コード内のバグなのか、それとも DB の問題なのか?)。

于 2013-01-27T21:24:02.647 に答える
0

これらのことをよりよくテストするための簡単な方法の 1 つは、構成クラスにデータベースにアクセスするためのオブジェクトを与えることです。これにより、実際のデータベース、または永続性が必要な場合は代わりにメモリに書き込むそのモックまたは軽量ファイルを使用して任意の構成を実行できます。例えば。

これは、定義済みのインターフェースを持つアダプターを作成することで実行できます。最初に作成するアダプターは、データベース用です。

構成オブジェクトを作成するときに、アダプターを渡します。定義済みのインターフェイスがあるため、構成クラスはそのインターフェイスを持つ任意のアダプターと連携できます。まずはデータベース。

次に、アダプターをモックするか、テスト用に独自のアダプターを作成します。テスト内では、データベース アダプターではなく、テスト アダプターを使用します。

次に、データベースに関係なく構成クラスを単体テストできます。

于 2012-10-15T13:16:55.343 に答える