web-dev-qa-db-ja.com

名前空間でのPHPUnitテストの編成

PHPUnitユニットテストを名前空間階層に編成するための2つのオプションが表示されます。これらの2つのアプローチの利点と欠点は何ですか?私が考慮していない明らかな欠陥があるので、それが明らかにより良い選択になるでしょうか?

\SomeFramework\Utilities\AwesomeClassのようなサンプルクラスを考えます。

  • アプローチ1:各TestCaseクラスを、対象のクラスと同じ名前空間に配置します。

    \SomeFramework\Utilities\AwesomeClassTest
    
    • 利点
      • PHPUnitテストを作成するための従来のアプローチと一致しています。
    • 短所
      • 柔軟性が低い。
      • 名前空間の使用の背後にある原則に違反しているようです-無関係なテストは同じ名前空間にグループ化されています。

  • アプローチ2:各TestCaseを、対象のクラスにちなんで名付けられた名前空間に配置します。

    \SomeFramework\Utilities\AwesomeClass\Test
    
    • 利点
      • さまざまなテストスイートなど、関連する複数のTestCaseクラスをグループ化する非常に簡単で明白な方法を提供します。
    • 短所
      • より深い、より複雑な階層になる可能性があります。
36
Wilco

私の提案する解決策とその背後にある理由:

フォルダレイアウト:

_.
├── src
│   ├── bar
│   │   └── BarAwesomeClass.php
│   └── foo
│       └── FooAwesomeClass.php
└── tests
    ├── helpers
    │   └── ProjectBaseTestClassWithHelperMethods.php
    ├── integration
    │   ├── BarModuleTest.php
    │   └── FooModuleTest.php
    └── unit
        ├── bar
        │   └── BarAwesomeClassTest.php
        └── foo
            └── FooAwesomeClassTest.php
_

_helpers/_フォルダーには、テストではないがテストコンテキストでのみ使用されるクラスが含まれています。通常、そのフォルダーにはBaseTestClassが含まれている可能性があり、おそらくプロジェクト固有のヘルパーメソッドと、再利用が容易なスタブクラスがいくつか含まれているため、モックはそれほど必要ありません。

_integration/_フォルダーには、より多くのクラスにまたがるテストとシステムの「より大きな」部分をテストするテストが含まれています。それほど多くはありませんが、本番クラスへの1対1のマッピングはありません。

_unit/_フォルダーは、1:1を_src/_にマップします。したがって、すべての製品クラスには、そのクラスのすべてのnitテストを含む1つのクラスがあります。

名前空間

アプローチ1:各TestCaseクラスを、対象のクラスと同じ名前空間に配置します。

このフォルダーアプローチは、アプローチ1を使用して、欠点の1つを解決する必要があります。純粋な1対1のマッピングで得られるよりも多くのテストを実行できる柔軟性がまだありますが、すべてが順序正しく配置されています。

名前空間の使用の背後にある原則に違反しているようです-無関係なテストは同じ名前空間にグループ化されています。

テストに「無関係」と思われる場合は、量産コードにも同じ問題があるのでしょうか?

テストが相互に依存していないのは事実ですが、テストは「近い」クラスをモックとして使用するか、DTOまたは値オブジェクトの場合は実際のクラスを使用する場合があります。だから私はつながりがあると思います。

アプローチ2:対象のクラスにちなんで名付けられた名前空間に各TestCaseを配置します。

これを行うプロジェクトはいくつかありますが、通常は少し異なって構成されています。

これは_\SomeFramework\Utilities\AwesomeClass\Test_ではなく_\SomeFramework\Tests\Utilities\AwesomeClassTest_であり、1:1マッピングを保持していますが、追加のテスト名前空間が追加されています。

追加のテスト名前空間

私の個人的な見解では、個別のテスト名前空間を持つことは好きではないので、その選択に対する賛成と反対の議論をいくつか見つけようとします。

テストは、クラスの使用方法に関するドキュメントとして機能する必要があります

実際のクラスが別の名前空間にある場合、テストはそのクラスを独自のモジュールの外で使用する方法を示します。

実際のクラスが同じ名前空間にある場合、テストはそのモジュール内からそのクラスを使用する方法を示します。

違いはごくわずかです(通常、「使用」ステートメントまたは完全修飾パスのカップル)。

PHP 5.5の代わりに$this->getMock(AwesomeClass::CLASS)と言う可能性がある場合、$this->getMock('\SomeFramework\Utilities\AwesomeClass')ではなく、すべてのモックにuseステートメントが必要になります。

私にとって、モジュール内での使用はほとんどのクラスにとってより価値があります

「プロダクション」名前空間の汚染

_new \SomeFramework\Utilities\A_と言うと、オートコンプリートでAwesomeClassAwesomeClassTestが表示される場合があり、それを望まない人もいます。外部で使用する場合、またはソースを出荷する場合。テストは出荷されないため、もちろん問題にはなりませんが、検討する必要があるかもしれません。

34
edorian

私が使用する3番目のオプションがあり、composer autoloading:Test名前空間を階層の最初のステップの後に挿入します。この場合、名前空間は\SomeFramework\Tests\Utilities\になります。そしてあなたのクラスは\SomeFramework\Tests\Utilities\AwesomeClassTestになります。

次に、テストを他のクラスと一緒に\SomeFramework\Testディレクトリに配置するか、別のディレクトリに配置できます。 composer.jsonのオートロード情報は次のようになります。

{
    "autoload": {
        "psr-0": { 
            "SomeFramework\\": "src/",
        }
    },
    "autoload-dev": {
        "psr-0": { 
            "SomeFramework\\Tests\\": "tests/"
        }
    }
}

3番目のアプローチの利点は次のとおりです。

  • テストと製品コードの分離
  • テストおよび本番クラス用の同様のフォルダー階層
  • 簡単な自動読み込み
16
chiborg

私は一貫性を維持するために最初のアプローチを好みます-PHPUnitプラクティスと他のプロジェクトで。さらに、テスト対象のクラスごとに1つのテストケースのみを作成します。それぞれを独自の名前空間に置くのはやり過ぎのようです。 KingCrunchが言ったように、テストするクラスは関連しているため、テストは関連しています。

多くの場合、テストケースにはフィクスチャなどのサポートファイルが必要ですが、それらはクラスの名前が付けられたサブディレクトリ/名前空間に簡単に編成され、複数のテストケースで共有されることがよくあります。

2番目の方法の大きな欠点の1つは、すべてのテストケースの名前がTestであり、いくつかの影響があることです。

  • 複数の開いているテストウィンドウはすべて同じ名前になります。
  • IDEの「名前でタイプを開く」機能(NetBeansではCTRL-O)は、テストには役に立ちません。
  • IDEの「go to test」キーのショートカット(NetBeansではCTRL-SHIFT-T)も失敗する可能性があります。
4
David Harkness