10

最終的には次のようになる方法があるとします。

class Pager
{
    private $i;

    public function next()
    {
        if ($this->i >= 3) {
            throw new OutOfBoundsException();
        }

        $this->i++;
    }
}

このクラスをどのように単体テストしますか。next()つまり、 PHPUnitを使用した3回目の呼び出しで例外がスローされるかどうかをテストしますか?私は自分の試みを答えとして追加しましたが、これが本当に進むべき道であるかどうかはわかりません。

4

5 に答える 5

8

null最初の2つの呼び出しでテストし、次のようにスローされる例外をテストするのはどうですか。

class PagerTest
{
    public function setUp()
    {
        $this->pager = new Pager();
    }

    public function testTooManyNextCalls()
    {
        $this->assertNull($this->pager->next());
        $this->assertNull($this->pager->next());
        $this->assertNull($this->pager->next());

        $this->setExpectedException('OutOfBoundsException');
        $this->pager->next();
    }
}
于 2012-10-13T17:21:39.567 に答える
4

ユニットテストを行うときは、実装の詳細をテストしないようにすることが非常に重要です。代わりに、コードのパブリックインターフェイスのみをテストするように制限する必要があります。なんで?実装の詳細は頻繁に変更されますが、APIはめったに変更されないためです。実装の詳細をテストするということは、それらの実装が変更されたときに常にテストを書き直す必要があり、これをやり続ける必要がないことを意味します。

では、これはOPのコードにとって何を意味するのでしょうか。Pager::nextpublicメソッドを見てみましょう。PagerクラスAPIを使用するコードは、例外をスローする必要があるかどうかをどのように決定するかを気にしません。何かが間違っている場合に実際に例外をスローするPager::nextことだけを気にします。Pager::next

メソッドがスローする決定にどのように到達するかをテストしたくありませんOutOfBoundsException-これは実装の詳細です。適切な場合にのみ、テストする必要があります。

したがって、このシナリオをテストするために、Pager::nextがスローされる状況をシミュレートします。これを実現するには、「テストシーム」と呼ばれるものを実装するだけです。..。

<?php
class Pager
{
    protected $i;

    public function next()
    {
        if ($this->isValid()) {
            $this->i++;
        } else {
            throw new OutOfBoundsException();
        }
    }

    protected function isValid() {
        return $this->i < 3;
    }
}

上記のコードでは、保護されたPager::isValidメソッドがテストシームです。これにより、テスト目的でラッチできるコード(名前の由来)の継ぎ目が公開されます。新しいテストシームとPHPUnitのモックAPIを使用すると、Pager::nextの無効な値に対して例外をスローするテスト$iは簡単です。

class PagerTest extends PHPUnit_Framework_TestCase
{
    /**
     * @covers Pager::next
     * @expectedException OutOfBoundsException
     */
    public function testNextThrowsExceptionOnInvalidIncrementValue() {
        $pagerMock = $this->getMock('Pager', array('isValid'));
        $pagerMock->expects($this->once())
                  ->method('isValid')
                  ->will($this->returnValue(false));
        $pagerMock->next();
    }
}

このテストでは、実装メソッドが現在の増分が無効であると判断する方法を特に気にしないことに注意してください。このテストは、呼び出されたときPager::isValidに返されるメソッドをモックするだけなので、パブリックメソッドが例外をスローするはずのときに例外をスローすることをテストできます。falsePager::next

PHPUnitモックAPIについては、PHPUnitマニュアルのTestDoublesセクションで詳しく説明されています。APIは、世界の歴史の中で最も直感的なものではありませんが、繰り返し使用することで、一般的に理にかなっています。

于 2012-10-13T17:38:47.947 に答える
1

これが私が現在持っているものですが、これを行うためのより良い方法があるかどうか疑問に思いました。

class PagerTest
{
    public function setUp()
    {
        $this->pager = new Pager();
    }

    public function testTooManyNextCalls()
    {
        for ($i = 0; $i < 10; $i++) {
            try {
                $this->pager->next();
            } catch(OutOfBoundsException $e) {
                if ($i == 3) {
                    return;
                } else {
                    $this->fail('OutOfBoundsException was thrown unexpectedly, on iteration ' . $i);
                }
            }

            if ($i > 3) {
                $this->fail('OutOfBoundsException was not thrown when expected');
            }
        }
    }
}
于 2012-10-13T16:48:10.960 に答える
1

次のようなものを使用できます。

class PagerTest extends PHPUnit_Framework_TestCase {

    /**
     * @expectedException OutOfBoundsException
     */
     public function testTooManyNextCalls() {
         $this->pager = new Pager();

         $this->pager->next();
         $this->pager->next();
         $this->pager->next();

         $this->assertTrue(false);
    }
}

3番目のメソッド呼び出しで例外がスローされた場合、常に失敗するassertステートメントに到達することはなく、テストに合格する必要があります。一方、例外がスローされない場合、テストは失敗します。

于 2012-10-13T17:10:52.717 に答える
0

値$this->iを例外のインスタンス化に渡すことができます。これは、例外のメッセージになります。

class Pager
{
    private $i;

    public function next()
    {
        if ($this->i >= 3) {
            throw new OutOfBoundsException($this->i);
        }

        $this->i++;
    }
}
$a=new Pager();
$a->next();
$a->next();
$a->next();
$a->next();

//outputs: "Exception: 3"
于 2012-10-13T16:57:54.907 に答える