是否有可能使用PHPUnit模拟对象期望调用magic __call()方法?

Jer*_*rne 29 php phpunit magic-methods symfony

我在测试中有一个模拟对象.现实对象,PageRepository,实现了使用__call()魔术方法,所以如果你调用$ pageRepository-> findOneByXXXX($ value_of_field_XXXX),它会在数据库中搜索该参数匹配的记录.

有没有办法模拟这种方法?

真正的方法调用看起来像这样:

$homepage = $pageRepository->findOneBySlug('homepage');
Run Code Online (Sandbox Code Playgroud)

测试看起来像这样:

$mockPageRepository->expects($this->any())
    ->method('findOneBySlug')
    ->will($this->returnValue(new Page()));
Run Code Online (Sandbox Code Playgroud)

但它不起作用 - PHPUnit没有发现方法调用.让它看到方法的唯一方法是在PageRepository中显式定义方法.

Joh*_*ess 44

PHPUnit getMock()接受第二个参数,一个带有要模拟的方法名称的数组.如果在此数组中包含方法名称,则模拟对象将包含具有该名称的方法,expects()并且朋友将使用该方法.

这甚至适用于未在"真实"类中定义的方法,因此类似下面的方法应该可以解决这个问题:

$mockPageRepository = $this->getMock('PageRepository', array('findOneBySlug'));
Run Code Online (Sandbox Code Playgroud)

请记住,您必须显式包含任何其他需要模拟的方法,因为为模拟对象定义了数组中指定的方法.

  • 请注意,如果您需要通过模拟构建器执行复杂的操作(例如禁用原始构造函数),则必须显式调用`setMethods()`例如`$ this-> getMockBuilder('ClassName') - > setMethods([' findById']) - > getMock();`因为*builder*上的`getMock()`不带任何参数. (4认同)

Ser*_*nov 5

我找到了更好的方法来做到这一点。仍然不完美,但您不必手动指定所有模拟类方法,只需指定魔术方法:

    $methods = get_class_methods(PageRepository::class);
    $methods[] = 'findOneBySlug';
    $pageRepositoryMock = $this->getMockBuilder(PageRepository::class)
        ->disableOriginalConstructor()
        ->disableOriginalClone()
        ->disableArgumentCloning()
        ->disallowMockingUnknownTypes()
        ->setMethods($methods)
        ->getMock();
Run Code Online (Sandbox Code Playgroud)