Phpunit: データプロバイダーはsetupBeforeClassの前に実行されます

作成日 2013年02月21日  ·  21コメント  ·  ソース: sebastianbergmann/phpunit

データプロバイダーは、静的setupBeforeClassが実行される前に呼び出されます。 それが逆であるべきだと思うなら。

使用事例:

  • アダプターのリストがあります。 一部のアダプタは、一部の環境(LinuxとWinなど)でのみサポートされています。
  • サポートされているアダプターのリストを一度初期化し、データプロバイダーを介してすべてのテストに渡したいのですが、
  • 私が想像できる最もクリーンな方法は、静的プロパティをsetupBeforeClassで初期化し、プロバイダーにそのプロパティを返すようにすることです。

問題は、プロバイダーが呼び出されたときにプロパティが初期化されないことです。

見つかったバージョン:3.7.14

最も参考になるコメント

@epdenouden JIT? JIT for PHPでテストしていますか、それとも私が知らないことがありますか? 申し訳ありませんが、少し混乱しています。 PHP7.xとPHP8.x、またはPHPUnit7.xとPHPUnit8.xについて話しているのですか?!

@MAChitgarha PHP8がジャストインタイムの_compiler_を取得しているので、あなたの混乱を理解しています。 私は同じ考えに基づいた新しいデータプロバイダー実装の用語を使用していました:ジャストインタイムの_loader_別名lazy-loading。 必要なときに、必要なものだけを初期化します。

これは、PHP言語自体のトリッキーな機能を使用しないため、今後のPHPバージョン8JITで正常に機能します。 私のすべての作業は、構成の解析、テストのロードと実行などをやり直すPHPUnitの奥深くにあります。

私が何もしていないように見える場合、私はそれを正しく行っています。 下げられたGCPまたはAWSの請求書を除いて。 💸

全てのコメント21件

データプロバイダーが静的である必要がない、または同じテストクラスである必要がないことを考えると、静的リソースをsetupBeforeClassで初期化できるように順序を強制することが本当に意味があるかどうかはわかりません。

アダプターを怠惰に初期化しないのはなぜですか? その場合、順序はまったく関係ありません。

データプロバイダーを実行しないと、テストメソッドが実行するテストの数がわかりません。 完璧な世界では、B / Cを破り、データプロバイダーがCountableを拡張するインターフェイスを実装するオブジェクトである必要があります。 そうすれば、これらの懸念を分離して、はるかにクリーンな状況にすることができます。

この@whatthejeffである、私たちがやってしまいます。 ただし、コンストラクターでの初期化は、プロバイダーから返されるときにパラメーターを配列でラップする必要があるため、少しクリーンになる可能性があります。

@sebastianbergmann okなぜ今までに呼ばれたのか理解できましたが、ドキュメントで言及するのはどうですか? (大丈夫なら変わるPRを開くことができます)。 オブジェクトを持つことが大いに役立つかどうかさえわかりません。私の元を見ると、あるプロバイダーから別のプロバイダーへの依存関係があります。

返信ありがとうございます。問題を解決します。

@vicb 、このためにドキュメント関連のPRを喜んでマージします。

シーンに少し遅れるかもしれませんが、初期化する必要のある依存関係がある場合は、 @dataProviderアノテーションを破棄し、代わりにyield使用します。

@srosato私はばかげています(私はyieldを使用していません)。 これを行う方法の簡単な例を教えてください。 ここでの例が適切でない場合は、 https://gist.github.com経由。

@dataProviderにセットアップコードが必要で、それほど大きくない場合は、文字列として指定し、テストでevalを指定できます。 例えば:

public function myProvider() {
    return [
        'new Klass("param 1", "param 2")',
        'new Klass("param 1", "param 2")',
    ];
}

/**
 * <strong i="8">@dataProvider</strong> myProvider
 */
public testMyFunction($instance_str) {
    $klass = eval("return {$instance_str};");
    # continue testing $klass ...
}

私の2セント:

静的プロパティに依存するデータプロバイダーの代わりに(不可能であることがわかっています)、必要なデータ/オブジェクトをsetUp()メソッドのテストクラスのクラスメンバーとして設定しています。
tearDown() 、それをnullに設定するか、複雑なオブジェクトがある場合は、 clear()メソッドを実装します。

テストクラス全体の依存関係が多すぎない限り、私はこのアプローチに満足しています。
ただし、そのような依存関係が1つか2つ以上ある場合は、全体的な設計を考え直す必要があるかもしれません。

具体的には、DB接続をsetUpBeforeClass()に設定されている静的プロパティとして使用し、接続が挿入される$queryBuildersetUp()クラスメンバーとして(代わりに)設定します。データプロバイダーに返します)。

解決策は、新しいプライベートメソッドを定義し、その中のstatic変数と同じ数の変数を定義することです。 次に、それらの1つが設定されているかどうかを確認し、設定されていない場合は、すべてを設定して、それらを返します(または譲ります)。 このように、プロバイダーが10個ある場合でも、_変数は1回だけ宣言されます_。 また、 setUpBeforeClass()またはsetUp()使用できます。

例でそれを見てください:

private static function getData()
{
    static $data, $anotherData;

    if (!isset($data)) {
        $data = new TestClass();
        $anotherData = [];
    }

    return [
        $data,
        // Or: clone $data
        $anotherData,
    ];
}

public static function setUpBeforeClass()
{
    list(self::$sampleJson, self::$sampleData) = self::getData(); 
}

public function sampleProvider()
{
    $data = self::getData();

    return [
        $data
    ];
}

@MAChitgarha昨日あなたのコメントに感謝します私はこのチケットについて知りました。 :)

私は#3736のデータプロバイダーロジックのリファクタリングに取り組んでいます。これにより、いくつかの一般的な問題が解決されます。

  • すべてのデータプロバイダーが読み込まれるため、実行の開始時にアクティビティがこのように急増することはなくなりました。
  • データプロバイダーは、フィクスチャsetUpBeforeClassおよびsetUp後に実行できます
  • 非静的データプロバイダーが可能になります
  • 発電機ははるかに効率的になります

@epdenoudenそれを聞いて幸せです! ;)リストの2番目の項目は良いものです。 それを待っています。

非静的データプロバイダーが可能になります

現在はできませんか? テストでは、静的データプロバイダーではなく、常に非静的データプロバイダーを使用しますが、問題なく正常に機能します(PHPUnit 7.5.6を使用)。 私が間違っている?

現在はできませんか? テストでは、静的データプロバイダーではなく、常に非静的データプロバイダーを使用しますが、問題なく正常に機能します(PHPUnit 7.5.6を使用)。 私が間違っている?

いいえ、あなたは正しいです! これを提起してくれてありがとう、私の言い回しは十分に正確ではありませんでした。 現在読み取っているデータプロバイダー処理コードの詳細:

private static function getDataFromDataProviderAnnotation($allTheParameters): ?iterable
    // code for locating the data provider
    // [...]
                if ($dataProviderMethod->isStatic()) {
                    $object = null;
                } else {
                    $object = $dataProviderClass->newInstance();
                }

    // code for preparing returned data rows
    // [...]
}

だからここに汚い小さな秘密があります:

  • 非静的データプロバイダーを使用でき、
  • それらは実際のinstanceofで呼び出されますが...
  • フィクスチャとテストに使用されるのは_同じインスタンスではありません_

データプロバイダーのリファクタリングについて考え、検証するための何かを私にくれました! オブジェクトインスタンスが同じタイプやクローンだけでなく、期待されるものであることを確認するために、テストを追加する必要があります。 ☕️と🍰あなたがアムステルダムにいるときは私に。

@MAChitgarhaインスタンスは実際に異なります: https

image

@epdenoudenしかし、失敗はありません! PHPUnit 7.5.13では、アサーションはエラーを生成しません。 このエラーをどのように取得しますか? 後方非互換性、つまり?

これは、私が取り組んでいる8.2に基づく遅延読み込みデータプロバイダーブランチにあります。 ヘッズアップをありがとう、次に7.5.xをチェックします。

これが機能する場合は、非静的プロバイダーメソッドの実装を明示的に要求していた他の古い問題に戻り、正確なユースケースをもう一度確認する必要があります。

いずれにせよ:あなたのコメントはすでに非常に有用なテストに影響を与えています:)

そして@MAChitgarhaはい、それはBCブレイクになります

@epdenoudenそれを待ちます。 いくつかの理由で、私のプロジェクトではPHPUnit7.5.13を使用しています。 しかし、私はそれを8.2。*にすぐに更新するつもりです。 そして、BCブレークを修正できれば、朗報です。 PHPUnit自体の構造がわからないので、何を変更したのかわかりませんが、修正は可能だと思います。 しかし、それはすべてあなた次第です! :)

そして、BCブレークを修正できれば、朗報です。 PHPUnit自体の構造がわからないので、何を変更したのかわかりませんが、修正は可能だと思います。 しかし、それはすべてあなた次第です! :)

非常に正当な理由なしに下位互換性の中断を導入することは、 @ sebastianbergmannが許可するものではないため、次のバージョンに入る前に修正される予定です。 PHPUnitは、PHPコミュニティでソフトウェアの品質を保護するために使用されるツールであり、私の個人的な遊び場ではありません。

そうです、テストのエンドユーザー/開発者として何を見たいかを教えてください。 このようなプロジェクトには、ボランティア開発者の大規模なプールがないことを覚えておいてください。

おもしろい事実:上記のテストは実際にバージョン7.xと8.xの両方で機能し、JITプロトタイプでは失敗します。

私が取り組んでいるコードは、まだ元のコードフローに非常に似ています。 したがって、バグの結果である可能性があります。さらにリファクタリングする必要のあるロジック、検索する必要のあるオブジェクトとPHPでのリフレクションに関する低レベルの問題、または単純なテストの結果である可能性があります。 🔬

@epdenouden JIT? JIT for PHPでテストしていますか、それとも私が知らないことがありますか? 申し訳ありませんが、少し混乱しています。 PHP7.xとPHP8.x、またはPHPUnit7.xとPHPUnit8.xについて話しているのですか?!

@epdenouden JIT? JIT for PHPでテストしていますか、それとも私が知らないことがありますか? 申し訳ありませんが、少し混乱しています。 PHP7.xとPHP8.x、またはPHPUnit7.xとPHPUnit8.xについて話しているのですか?!

@MAChitgarha PHP8がジャストインタイムの_compiler_を取得しているので、あなたの混乱を理解しています。 私は同じ考えに基づいた新しいデータプロバイダー実装の用語を使用していました:ジャストインタイムの_loader_別名lazy-loading。 必要なときに、必要なものだけを初期化します。

これは、PHP言語自体のトリッキーな機能を使用しないため、今後のPHPバージョン8JITで正常に機能します。 私のすべての作業は、構成の解析、テストのロードと実行などをやり直すPHPUnitの奥深くにあります。

私が何もしていないように見える場合、私はそれを正しく行っています。 下げられたGCPまたはAWSの請求書を除いて。 💸

このページは役に立ちましたか?
0 / 5 - 0 評価