40

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

次のようなサンプル クラスを考えてみましょう\SomeFramework\Utilities\AwesomeClass

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

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

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

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

3 に答える 3

41

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

フォルダ レイアウト:

.
├── 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/。したがって、すべてのプロダクション クラスには、そのクラスのすべての単体テストを含む 1 つのクラスがあります

名前空間

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

このフォルダー アプローチは、アプローチ 1の欠点の 1 つを解決するはずです。純粋な 1:1 マッピングよりも多くのテストを柔軟に行うことができますが、すべてが整然と配置されています。

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

テストが「無関係」であると感じた場合、製品コードに同じ問題がある可能性がありますか?

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

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

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

ではありません\SomeFramework\Utilities\AwesomeClass\Test\SomeFramework\Tests\Utilities\AwesomeClassTest、1:1 のマッピングは維持されますが、テスト用の名前空間が追加されています。

追加のテスト名前空間

私の個人的な見解は、テスト用の名前空間を別々にするのは好きではないということです。そのため、その選択に対する賛否両論をいくつか見つけようと思います。

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

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

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

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

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

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

「プロダクション」ネームスペースの汚染

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

于 2012-08-27T12:02:11.687 に答える
20

私が使用していて、composer の自動読み込みにうまく適合する 3 番目のオプションがあり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 番目のアプローチの利点は次のとおりです。

  • テストと本番コードの分離
  • テストと本番クラスの同様のフォルダー階層
  • 簡単なオートロード
于 2014-01-07T09:55:37.437 に答える
4

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

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

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

  • 複数の開いているテスト ウィンドウはすべて同じ名前になります。
  • IDE の「名前でタイプを開く」機能 (NetBeans では CTRL-O) は、テストには役に立ちません。
  • IDE の「テストに進む」キー ショートカット (NetBeans では CTRL-SHIFT-T) も失敗する可能性があります。
于 2012-08-25T19:13:20.990 に答える