抽象クラスのテスト


144

PHPUnitで抽象クラスの具象メソッドをテストするにはどうすればよいですか?

テストの一部として何らかのオブジェクトを作成する必要があると思います。ただし、これのベストプラクティスや、PHPUnitでこれが許可されているかどうかはわかりません。


10
おそらく、受け入れられた回答を変更することを検討する必要があります。
ジェイコブ

1
多分stackoverflow.com/a/2947823/23963が役立つでしょう。
Nigel Thorne、

回答:


240

抽象クラスは具象メソッドを持つことができ、この具象メソッドをテストできるため、抽象クラスのユニットテストは必ずしもインターフェースのテストを意味しません。

一部のライブラリー・コードを作成するときに、アプリケーション層で拡張することが予想される特定の基本クラスがあることはそれほど珍しくありません。また、ライブラリコードが確実にテストされるようにするには、抽象クラスの具象メソッドをUTする手段が必要です。

個人的には、私はPHPUnitを使用しており、この種のテストに役立つように、いわゆるスタブとモックオブジェクトを用意しています。

PHPUnitマニュアルから直接

abstract class AbstractClass
{
    public function concreteMethod()
    {
        return $this->abstractMethod();
    }

    public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
    public function testConcreteMethod()
    {
        $stub = $this->getMockForAbstractClass('AbstractClass');
        $stub->expects($this->any())
             ->method('abstractMethod')
             ->will($this->returnValue(TRUE));

        $this->assertTrue($stub->concreteMethod());
    }
}

モックオブジェクトはあなたにいくつかのものを与えます:

  • 抽象クラスを具体的に実装する必要はなく、代わりにスタブを使用できます
  • 具体的なメソッドを呼び出して、それらが正しく実行されることを主張することができます
  • 具体的なメソッドが実装されていない(抽象的な)メソッドに依存している場合は、will()PHPUnitメソッドを使用して戻り値をスタブできます。

38

それは良い質問です。私もこれを探していました。
幸いなことに、PHPUnitにはすでにgetMockForAbstractClass()このケース用のメソッドがあります。たとえば、

protected function setUp()
{
    $stub = $this->getMockForAbstractClass('Some_Abstract_Class');
    $this->_object = $stub;
}

重要:

これにはPHPUnit> 3.5.4が必要です。以前のバージョンにはバグがありまし

最新バージョンにアップグレードするには:

sudo pear channel-update pear.phpunit.de
sudo pear upgrade phpunit/PHPUnit

面白そうに聞こえますが、モックに対してテストしますか?テストはどのようなものですか?IE:テストケースでモックを拡張し、拡張されたテストクラスに対してテストしますか?
stefgosselin '19年

34

PHP 7以降、匿名クラスのサポートが追加されていることに注意してください。これにより、抽象クラスのテストをセットアップするための追加の手段が提供されます。これは、PHPUnit固有の機能に依存しないものです。

class AbstractClassTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var AbstractClass
     */
    private $testedClass;

    public function setUp()
    {
        $this->testedClass = new class extends AbstractClass {

            protected function abstractMethod()
            {
                // Put a barebones implementation here
            }
        };
    }

    // Put your tests here
}

4
これありがとうございます!PHPUnitで匿名クラスを使用すると、さまざまなテストを柔軟に作成できます。
アリスワンダー

1

エラン、あなたの方法はうまくいくはずですが、実際のコードの前にテストを書く傾向に反します。

私が提案するのは、問題の抽象クラスの非抽象サブクラスの望ましい機能についてテストを記述し、次に抽象クラスと実装サブクラスの両方を記述して、最後にテストを実行することです。

テストでは、抽象クラスの定義済みメソッドをテストする必要がありますが、常にサブクラスを介してテストする必要があります。


私は任意の答えとして見つけます:あなたは共通の 'foo()'メソッドを持つ抽象クラス 'A'を持っています。この「foo()」メソッドは、すべて「B」および「C」クラス全体で使用されており、どちらも「A」から派生しています。「foo()」をテストするためにどのクラスを選択しますか?
user3790897 2017

1

ネルソンの答えは間違っています。

抽象クラスでは、メソッドのすべてが抽象クラスである必要はありません。

実装されたメソッドは、テストする必要があるものです。

あなたができることは、ユニットテストファイルに偽のスタブクラスを作成し、抽象クラスを拡張して、機能なしで必要なものだけを実装し、もちろんそれをテストすることです。

乾杯。


0

抽象クラスにすでに実装されているメソッドで単体テストを実行するためだけに抽象クラスをサブクラス化したくない場合は、フレームワークで抽象クラスをモックできるかどうかを確認してみてください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.