23

DateTimePHPUnit または Behat テストの期間中、インスタンス化されたすべてのインスタンスの時間を設定できるようにしたいと考えています。

時間に関連するビジネス ロジックをテストしています。たとえば、クラスのメソッドは過去または未来のイベントのみを返します。

できればやりたくないこと:

  1. ラッパーを書き、コード全体のDateTime代わりにこれを使用します。DateTimeこれには、現在のコード ベースを少し書き直す必要があります。

  2. テスト/スイートが実行されるたびに動的にデータセットを生成します。

DateTime質問は次のとおりです。要求されたときに常に特定の時間を提供するように s の動作をオーバーライドすることは可能ですか?

4

5 に答える 5

23

DateTimeテストで必要なメソッドをスタブして、期待値を返す必要があります。

$stub = $this->getMock('DateTime');
$stub->expects($this->any())
     ->method('theMethodYouNeedToReturnACertainValue')
     ->will($this->returnValue('your certain value'));

https://phpunit.de/manual/current/en/test-doubles.htmlを参照してください

コードにハードコードされているためにメソッドをスタブ化できない場合は、以下を参照してください。

が呼び出されるたびにコールバックを呼び出す方法を説明しnewます。次に、DateTime クラスを固定時刻を持つカスタム DateTime クラスに置き換えることができます。別のオプションは、http://antecedent.github.io/patchworkを使用することです

于 2011-10-31T10:46:02.863 に答える
2

DateTime()次のように明示的にインスタンス化するように実装を変更できますtime()

new \DateTime("@".time());

これは、クラスの動作を変更しません。しかし、名前空間付きの関数を提供することでモックtime()できるようになりました:

namespace foo;
function time() {
    return 123;
}

そうするために、私のパッケージphp-mock/php-mock-phpunitを使用することもできます。

namespace foo;

use phpmock\phpunit\PHPMock;

class DateTimeTest extends \PHPUnit_Framework_TestCase {

    use PHPMock;

    public function testDateTime() {
        $time = $this->getFunctionMock(__NAMESPACE__, "time");
        $time->expects($this->once())->willReturn(123);

        $dateTime = new \DateTime("@".time());
        $this->assertEquals(123, $dateTime->getTimestamp());
    }
}
于 2016-04-22T12:39:07.740 に答える
2

@Gordonがすでに指摘したことに加えて、現在の時間に依存するコードをテストする、かなりハックな方法が1つあります。

現在の時刻などを要求できるクラスを自分で作成する必要があるという問題を回避できる「グローバル」値を取得する保護されたメソッドを1つだけモックアウトします(これはよりクリーンですが、phpでは議論可能です/人々がそれをしたくないのは理解できます)。

それは次のようになります。

class Calendar {
    public function getCurrentTimeAsISO() {
        return $this->currentTime()->format('Y-m-d H:i:s');
    }

    protected function currentTime() {
        return new DateTime();
    }
}

class CalendarTest extends PHPUnit_Framework_TestCase {
    public function testCurrentDate() {
        $cal = $this->getMockBuilder('Calendar')
            ->setMethods(array('currentTime'))
            ->getMock();
        $cal->expects($this->once())
            ->method('currentTime')
            ->will($this->returnValue(
                new DateTime('2011-01-01 12:00:00')
            )
        );
        $this->assertSame(
            '2011-01-01 12:00:00',
            $cal->getCurrentTimeAsISO()
        );
    }
}
于 2011-11-02T12:30:44.307 に答える