8

私はPHPUnitテストを書いています。そこでは、いくつかの依存関係をモックする必要がありますが、それでも以前と同じように機能するために、いくつかのメソッドが必要です。つまり、私は持っています:

class Dependency {
// some stuff not important for the test
  public function thisOneINeed() {
   /// complex code
  }
// some more stuff
}

だから私はこのようなことをしていました:

// prepare mock object
$dep = $this->getMockBuilder('Dependency')->disableOriginalConstructor()->getMock();
// mock out some other method that should return fixed value
$dep->expects($this->any())->method("shouldGetTrue")->will($this->returnValue(true));
// run test code, it will use thisOneINeed() and shouldGetTrue()
$result = $testSubject->runSomeCode($dep);
$this->assertEquals($expected, $result);

そして、メソッドがモックアウトされていることを除いて、すべてが正常であるため、複雑なコードを実行できず、正しく機能thisOneINeed()するために実行する必要があります。runSomeCode()そのコードは thisOneINeed()他のメソッドを呼び出しませんが、適切なテストに必要であり、固定値を返さないため、静的なreturnValue()をそこに置くことはできません。returnValue()また、AFAIK PHPunitには、 「親を呼び出す」というようなメソッドはありません。ありますreturnCallback()が、私が見る限り、「親クラスに対してこのメ​​ソッドを呼び出す」と言う方法はありません。

のすべてのメソッドのリストを作成し、そこからDependency削除thisOneINeedして、モックを作成するときに渡すことsetMethods()ができますが、そのアプローチは好きではなく、ぎこちなく見えます。

私もこれを行うことができます:

class MockDependency extends Dependency
{
    // do not let the mock kill thisOneINeed function
    final public function thisOneINeed()
    {
        return parent::thisOneINeed();
    }
}

次に、を使用MockDependencyしてモックオブジェクトを作成します。これも機能しますが、手動でモックを作成する必要はありません。

それで、これを行うためのより良い方法はありますか?

4

4 に答える 4

9

PHPUnitのモックビルダーを使用したい場合は、すべてのメソッドの配列を作成し、必要なメソッドを削除して、それをsetMethodsに渡すことがまさに必要なことだと思います。

個人的には、多くの場合、必要なときにメソッドを追加できるReflectionClassのサブクラスがあると便利だと思いました。

class MyReflectionClass extends ReflectionClass
{
    public function getAllMethodNamesExcept(array $excluded)
    {
        $methods = array_diff(
            get_class_methods($this->name), 
            $excluded
        );
        return $methods;
    }
}

やりたいことをサポートする別のモックフレームワークを使用することもできます。たとえば、PhakeにはthenCallParentメソッドがあります。メソッドに渡されたパラメーターをキャプチャできるようにする必要があったため、最近Phakeを使い始めました。それは十分に文書化されており、試す価値があります。

于 2012-06-07T16:14:18.897 に答える
1

保護されたメソッドをモックする必要がありました。これは、ReflectionClassを実装するZachの回答のわずかに変更されたバージョンです。

$class = new ReflectionClass(\Foo\Bar::class);

// Get just the method names:
$methods = array_map(function($m){return $m->name;}, $class->getMethods());

$methodsToMock = array_diff(
    $methods,
    array("baz", "qux") // don't mock these.
);

$mockObj = $this->getMockBuilder("\Foo\Bar")
    ->setConstructorArgs(array($this->foo))
    ->setMethods($methodsToMock)
    ->getMock();

$mockObj->baz(); // run as normal.
$mockObj->qux(); // run as normal.
$mockObj->foobar(); // mocked.
于 2020-03-20T13:01:07.497 に答える
0

と呼ばれるモックビルダーメソッドがありますsetMethodsExcept()。これは(引用):

「モックビルダーオブジェクトで呼び出して、他のすべてのパブリックメソッドを置き換えるときに構成可能なテストダブルに置き換えられないメソッドを指定できます。これはonlyMethods()とは逆に機能します。」

参照:https ://phpunit.readthedocs.io/en/9.5/test-doubles.html

于 2021-09-29T06:47:51.520 に答える
0

setMethods()PHPUnitの最後のバージョンでは非推奨になっているため、もう1つの例です。

use Tests\TestCase;

class MyTestClass extends TestCase
{
    public function testMyMethodNotMock()
    {
         $myMockMethods = ['methodOne','methodTwo'];
         $myClassMock = $this->getMockBuilder(MyClass::class)
                             ->setConstructorArgs(['args1'])
                             ->onlyMethods($myMockMethods)
                             ->getMock();
         $this->assertTrue($myClassMock->methodNotMock());
     }
}
于 2022-02-21T10:24:15.423 に答える