PHP中的模拟静态方法

问题描述 投票:1回答:1

我的目标是能够为倡导静态方法的单元测试编写单元测试:

  1. 可维护性-我希望代码能随着时间的流逝而变得易于遵循,理解和调试。
  2. 性能-如果可能,我希望我们的测试速度不会受到技术债务的影响。

约束:我们不能将静态方法重构为实例方法。我可能会建议这是第一件事,但是我正在寻找一种选择/替代方案和意见。

测试静态方法有点麻烦。曾经有一段时间我们可以使用phpunit做到这一点。 Mockery支持通过static methods测试aliasing的方法,但不建议这样做。我发现运行这些类型的测试可能非常慢。 (因此,目标2)。

[不幸的是,如果您有相当数量的代码依赖于使用静态方法的其他代码,则您将承担自己的债务。有一些使用call_user_funchttps://medium.com/@nihon_rafy/how-to-mock-static-methods-for-unit-tests-in-php-18b2a11458d0)和forward_static_call_array()http://miljar.github.io/blog/2014/01/29/phpunit-testing-static-calls/)的技术,但我发现自己很难遵循此代码。

我想提供替代动态选项,类似于上面的内容。

class LegacyClass {
    public static function staticMethod($a, $b, $c) {
        return QueryBuilder::where($a, $b, $c)->getAll();
    }

}

class ClassToTest {
    public function test($a, $b, $c) {
        return LegacyClass::staticMethod($a+1, $b+2, $c+3);

}

对此的更改=>

class LegacyClass {
    public static function staticMethod($a, $b, $c) {
        return QueryBuilder::where($a, $b, $c)->getAll();
    }

}

class ClassToTest{
    // @var string fully qualified class name
    private $legacyClass = LegacyClass::class;
    public function test($a, $b, $c) {
        return {$this->legacyClass}::staticMethod($a+1, $b+2, $c+3);

}

现在,通过以上操作,我们可以模拟LegacyClass,获取该模拟的类名,并使用Reflection设置私有$legacyClass变量。

关于这个,我的问题:

  1. 以上哪个选项是最可维护的解决方案?
  2. 是否有更好的替代方案可以实现既定目标? (如果可以,我可以追加)

谢谢您的输入!

unit-testing mocking phpunit static-methods
1个回答
0
投票

我经常回想的解决方案是创建“中间人”类。我将其用于静态函数调用,还用于在代码中间创建new Object();的情况。

本质上,您只是将问题转移到了其他地方,这看起来似乎不是一个很好的解决方案,但是您只需将一行移开即可使ClassToTest易于测试。

简而言之;我要上一个新课(StaticFunctionCallerClass)。该类只有一个函数,只有一行。

class StaticFunctionCallerClass {
    public function test($a, $b, $c) {
        return LegacyClass::staticMethod($a+1, $b+2, $c+3);

}

现在您可以在ClassToTest中实例化此类(因此可以在测试中对其进行模拟)。因此,您可以测试其周围的所有逻辑,甚至可以测试是否使用正确的信息调用了新的StaticFunctionCallerClass

这里的缺点是它使新的StaticFunctionCallerClass难以测试代码。您可以在LegacyClassTest中调用此类,以测试调用是否正确完成,这也许不是一个很干净的选择,但确实可以完成工作。

© www.soinside.com 2019 - 2024. All rights reserved.