web-dev-qa-db-ja.com

抽象クラスのテスト

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

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

137
Mez

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

いくつかのライブラリコードを記述するときに、アプリケーションレイヤで拡張することが予想される特定の基本クラスを持つことはそれほど珍しいことではありません。また、ライブラリコードがテストされていることを確認する場合は、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メソッドで戻り値をスタブすることができます
230

それは良い質問です。私もこれを探していました。
幸いにも、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
36
takeshin

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
}
25
GordonM

Eran、メソッドは機能するはずですが、実際のコードの前にテストを書く傾向に反します。

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

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

1
Bruno

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

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

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

できることは、単体テストファイルに偽のスタブクラスを作成し、抽象クラスを拡張し、機能をまったく使用せずに必要なものだけを実装し、それをテストすることです。

乾杯。

1
skqr

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

0
hangy