3

我有一门课要在稍后的测试中模拟:

class Original {
  function calculate($a) { ... }
}

在测试中:

$mock = $this->getMock('Original',['calculate']);
$mock->expcets($this->any())
     ->will($this->returnValueMap([ 
      [1,'ABC'],
      [2,'BCD']
      // somehow tell $mock to call the original calculate() here
);

我想告诉在某些条件$mock下回退到原来calculate()的,例如,如果参数不匹配任何提供的检查。正如我从阅读 PhpUnit 代码中了解到的那样,如果找不到匹配项,调用程序只会返回 null :-?

4

5 回答 5

2

Mock 的重点是不要调用原始文件,因为它具有您无法控制测试的依赖项。当您想实际测试 calculate() 函数时,请调用测试并使用带有设置参数的普通代码来获得您想要的响应。

class Original {
  function calculate($a) { ... }
}

$mock = $this->getMock('Original',['calculate']);
$mock->expects($this->any())
     ->will($this->returnValueMap([ 
        [1,'ABC'],
        [2,'BCD']

$Orig = new Original();
$this->assertEquals(4, $Orig->calculates('2 * 2');
于 2013-09-23T14:42:49.923 回答
2
$mock = $this->getMockBuilder(Original::class)
            ->setMethodsExcept(['calculate'])->disableOriginalConstructor()
            ->getMock();

无论如何,这将调用原始的计算函数。

于 2020-10-19T13:13:46.190 回答
0

您可以通过使用回调来确定返回值来做到这一点。如果参数与任何固定值都不匹配,请进行实际调用:

$mock = $this->getMock('Original',['calculate']);
$mock->expects($this->any())
 ->will($this->returnCallback(function($argument) { 
    $values = array(
        1 => 'ABC',
        2 => 'BCD'
    );
    if (isset($values[$argument]) {
       return $values[$argument];
    } else {
       return (new Original)->calculate($argument);
    }
});

作为旁注,需要这可能是测试过于笼统的一个简单原因。每个测试都应该检查您的系统在非常具体的情况下是如何工作的。

问候

于 2013-09-24T20:29:11.323 回答
0

您只能指定要模拟的方法。这样,您未指定的方法遵循原始逻辑:

    $myStubObject = $this
      ->getMockBuilder(Original::class)
      ->setMethods(["anyButCalculate"])
      ->getMock();

    $myStubObject
      ->method('calculate')
      ->withAnyParameters()
      ->willReturn("expectedResultFromOriginalLogic");
于 2020-06-26T09:38:20.240 回答
0

如果您使用的模拟系统是 PHP 的Mockery,您也可以将 Mock 设置为“部分”。当你这样做时,所有不是shouldReceive()d 的方法都会调用原始的底层方法。

从文档:

当我们想要对类的某些方法进行存根、设置期望或监视,但为其他方法运行实际代码时,部分双精度数很有用。

我们所说的运行时部分,包括创建一个测试替身,然后告诉它自己做部分。任何未告知 double 允许或期望的方法调用,都将像在对象的普通实例上那样操作。

class Foo {
    function foo() { return 123; }
}

$foo = mock(Foo::class)->makePartial();
$foo->foo(); // int(123);

$foo->shouldReceive('foo')->andReturn(456);
$foo->foo(); // int(456)
于 2022-02-09T09:58:43.583 回答