PHPUnit - 模拟外部静态方法

5

我正在努力对商店系统的一个模块进行单元测试。该商店系统使用静态方法,我必须在要测试的函数中调用这些方法。

public function toTest() {
    $value = \Context::getData();
    return $value;
}

现在我该如何对该函数进行单元测试并模拟这个静态调用呢?我尝试使用AspectMock,但失败了,因为它显然需要访问原始的\Context类,而这是不可能的,因为它是一个外部系统。我还尝试使用class_alias创建自己的Context类,但也失败了,因为我需要根据正在测试的函数不同而产生不同的Context输出。对于不同的测试多次设置class_alias也行不通,因为相同的类不能被多次声明,而且@runTestsInSeparateProcesses没有预期的效果。
编辑:提供的所有重复内容都没有解决我的问题,因此我认为这不是重复内容。由于无法访问商店系统代码,尤其是像这样难以维护的代码,PHP并不容易进行单元测试。此外,我找到的解决方案应该可以帮助其他具有类似设置的人。

相信这是一个重复的问题,已经存在于stackoverflow上:在PHP中模拟静态方法 - Diogo Santo
我不知道这是否是您代码的现实示例,但如果是,那么这里没有太多需要测试的内容。相反,您应该测试 getData() 方法。 - jeroen
@DiogoSanto 这个重复是为了嘲笑一个将会出现在我自己代码中而不是在像这里这样的外部系统中的方法。至少就我所理解的而言。 - alobeejay
@jeroen getData方法不是我自己的,所以我无法测试它。此外,这只是一个非常简化的例子。我在$value之间做一些事情。 - alobeejay
在这种情况下,我会将对\Context::getData()的调用移动到一个单独的私有方法中(几乎就像你现在所做的那样...),以便您可以轻松地模拟该新方法来测试您的toTest()方法。 - jeroen
显示剩余2条评论
1个回答

4
我可以使用Mockery库解决我的问题。我尝试了几种方法,但都没有奏效。有了Mockery,一切似乎都变得可能了。这个链接真的很有帮助:https://robertbasic.com/blog/mocking-hard-dependencies-with-mockery/ 你可以轻松地模拟不属于你的类的静态调用:
public function methodToTest() {
    return \Context::getData();
}

public function testMethodToTest() {
    m::mock('alias:\Context')
        ->shouldReceive('getData')
        ->andReturn('foo');
}

甚至可以针对您无法访问的类进行实例化:

public function methodToTest() {
    $obj = new \Category(5);
    return $obj->id;
}

public function testMethodToTest() {
    m::mock('overload:\Category')
        ->shouldReceive('__construct')
        ->with(5)
        ->andSet('id', 5);
}

但是您必须记住,在类的开头需要使用两个phpunit注释:

* @runTestsInSeparateProcesses
* @preserveGlobalState disabled

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接