通过官方文档以及实践得知,含有静态方法的类如果需要mock,就要使用前缀 alias: ,但是随之而来有个问题是后面无法调用这个类本身的方法,所以通过阅读源码可以使用以下方法来实现(注意!!! 此方法无法生成覆盖率):
1.创建 Helpers 类进行封装
<?php
use Mockery;
use Mockery\Generator\MockConfigurationBuilder;
class Helpers
{
/**
* Mock static class, you can call the original method and mock the method
* mock 静态类,既可以调用原来的方法,又可以 mock 方法
* @param string $class
* @param string $cloneClassNameSuffix
* @return Mockery\Mock
* @throws \Exception
*/
public static function mockAliasPartial($class, $classRealPath, $cloneClassNameSuffix = 'UnitOrigin') {
$sourceCode = file_get_contents($classRealPath);
preg_match('/class\s+([A-Z]\w+)/', $sourceCode, $match);
$className = $match[1] ?? '';
if (empty($className)) {
throw new \Exception('get class name failed!');
}
// update class name
$cloneSourceCode = preg_replace('/class\s+([A-Z]\w+)/', 'class ' . $className . $cloneClassNameSuffix, $sourceCode, 1);
// update self:: call
$cloneSourceCode = str_replace('self::', 'static::', $cloneSourceCode);
eval("?>" . $cloneSourceCode);
$builder = new MockConfigurationBuilder();
$builder->setInstanceMock(true);
$builder->setName($class);
$target = '\\' . $class . $cloneClassNameSuffix;
return Mockery::mock($target, $builder)->makePartial();
}
}
2.创建静态类
class Test
{
public static function getName($name) {
if (empty($name)) {
return 'default_name';
}
return $name;
}
}
3.测试运行
<?php
use PHPUnit\Framework\TestCase;
class UniTest extends TestCase
{
public function testAliasPartial() {
$mock = Helpers::mockAliasPartial(Test::class, './Test.php');
$actual1 = Test::getName('');
echo PHP_EOL;
$mock->shouldReceive('avatar_small')->andReturn('fake name');
$actual2 = Service::getName('');
$this->assertEquals('default_name', $actual1);
$this->assertEquals('fake name', $actual2);
}
}