未被模拟的方法无法有期望
稍后我会详细介绍,但是这个:
$mock = $this->getMockForTrait(EmployeeAttendenceTrait::class)
如果没有模拟方法,那么$mock
就相当于:
class Testing extends PHPUnitsInternalMockStub
{
use EmployeeAttendenceTrait;
}
$mock = new Testing;
检查错误信息
错误信息如下:
尝试配置无法配置的方法getOfficeDays,因为它不存在、未指定、是final或是static
让我们逐个可能性来看(几乎是按顺序)
不存在
代码明显有一个名为getOfficeDays
的方法 - 如果不确定,使用get_class_methods可以澄清:
<?php
use PHPUnit\Framework\TestCase;
class SOTest extends TestCase
{
public function testMethods()
{
$mock = $this->getMockForTrait(EmployeeAttendenceTrait::class);
print_r(get_class_methods($mock));
}
}
这将输出:
R 1 / 1 (100%)Array
(
[0] => __clone
[1] => expects
[2] => method
[3] => __phpunit_setOriginalObject
[4] => __phpunit_getInvocationMocker
[5] => __phpunit_hasMatchers
[6] => __phpunit_verify
[7] => isLate
[8] => getOfficeDays
)
Time: 569 ms, Memory: 12.00MB
There was 1 risky test:
1) SOTest::testMethods
This test did not perform any assertions
所以不是那个。
最终确定
public function getOfficeDays(): array {
该方法签名明显没有
将方法声明为final,所以不是那个问题。
或者是静态的
public function getOfficeDays(): array {
方法签名明显
也不是静态的 - 所以也不是那个问题。
未指定
通过逻辑推断,这就是问题所在 - 这是唯一需要对使用phpunit有些了解的问题。
getMockForTrait的文档(已加重)如下:
getMockForTrait() 方法返回一个使用指定 trait 的模拟对象。给定 trait 的所有抽象方法都将被模拟。这允许测试 trait 的具体方法。
由于没有任何 trait 方法是抽象的,因此不希望使用问题中的语法模拟任何方法。更深入地查看
getMockForTrait的方法签名,会发现它有更多参数:
/**
* Returns a mock object for the specified trait with all abstract methods
* of the trait mocked. Concrete methods to mock can be specified with the
* `$mockedMethods` parameter.
*
* @throws RuntimeException
*/
public function getMockForTrait(
string $traitName,
array $arguments = [],
string $mockClassName = '',
bool $callOriginalConstructor = true,
bool $callOriginalClone = true,
bool $callAutoload = true,
array $mockedMethods = [],
bool $cloneArguments = true): MockObject
有一个参数用于指定显式模拟的方法,因此可以这样编写测试:
class SOTest extends TestCase
{
public function testMethods()
{
$mock = $this->getMockForTrait(
EmployeeAttendenceTrait::class,
[], # These
'', # are
true, # the
true, # defaults
true, #
['getOfficeDays']
);
$mock->expects($this->once())
->method('getOfficeDays')
->willReturn([]);
$today = new DateTime(); // or whatever is appropriate
$this->assertTrue($mock->isLate($today));
}
}
将生成一个有效的模拟对象并允许测试运行。