4

次の実装が与えられます:

class Foo {
    public function helper() {
        // Does something with external side effects, like updating
        // a database or altering the file system.
    }

    public function bar() {
        if ($this->helper() === FALSE) {
            throw new Exception(/* ... */);
        }
    }
}

Foo::bar()テスト中に副作用を発生させずに単体テストを行うにはどうすればよいFoo::helper()ですか?

私はモックFooとスタブができることを知っていますFoo::helper()

public function testGoodBar() {
    $mock = $this->getMock('Foo', array('helper'));
    $this->expects($this->once())
        ->method('helper')
        ->will($this->returnValue(TRUE));

    $this->assertTrue($mock->bar());
}

...しかし、これにより、副作用を引き起こす可能性のある他のメソッドを導入するコード変更に対して、テストが広く開かれたままになります。その後、更新せずにテストを再実行すると、テスト自体に永続的な副作用が発生します。

Fooまた、すべてのメソッドがモックされて副作用が発生しないように、モックすることもできます。

public function testGoodBar() {
    $mock = $this->getMock('Foo');
    $this->expects($this->once())
        ->method('helper')
        ->will($this->returnValue(TRUE));

    $this->assertTrue($mock->bar());
}

...しかし、Foo::bar()それは私たちがテストしたい方法なので、それは悪いことです。

私が思いついた唯一の解決策は、テスト対象のメソッドを除くすべてのメソッドを明示的にモックすることです。

public function testGoodBar() {
    $mock = $this->getMock('Foo', array_diff(
        get_class_methods('Foo'),
        'bar'
    ));

    $this->expects($this->once())
        ->method('helper')
        ->will($this->returnValue(TRUE));

    $this->assertTrue($mock->bar());
}

...しかし、これは厄介なようで、明らかな何かが欠けているように感じます。

4

2 に答える 2

5

(この回答では、質問の下のコメントを考慮に入れてください。)

副作用を発生させることが唯一の目的であるクラスを拡張する場合、すべての拡張コードで副作用も発生することが予想されます。したがって、テストでそれを考慮し、副作用のあるコードをテストできる環境をセットアップする必要があります(つまり、このテストのためにmemcachedインスタンスを起動して実行します)。

これを(当然のことながら)望まない場合は、モック可能な方法で副作用クラスのラッパーとしてコードを作成することをお勧めします。したがって、Foo::__construct副作用を生成するクラスのインスタンスまたはファクトリを受け入れるので、テストでそれをモックして、副作用のないコードのみをテストできます。

于 2012-11-06T16:22:09.843 に答える
-1

この場合、helper()が呼び出すメソッドのテストにもっと関心があり、bar()にはあまり関心がないようです。

メソッドが多くのことを行う場合、それを分割して他のメソッドにそれらのことを行わせるのは良いことです。これを行うと、以前と同じ出力が期待されますが、コードはより管理しやすい部分に分割されます。最初に最も小さい部分をテストすることが重要です。bar()をテストするときは、それほどテストする必要がないので、何度も何度もモックする必要はありません。多くの場合がhelper()のサポートメソッドでカバーされるためです。

于 2012-11-06T15:49:24.227 に答える