PHP:如何制作可测试的静态方法

我决定制作自己的穷人的ORM框架.由于我不知道如何去做,我决定在测试之前开发.
Github.在按照我想要的方式工作之后,我意识到我的代码是不可测试的,因为我的查询类和BaseModel的静态方法之间存在紧密耦合.

所以我想到了一些让它可测试的方法:

>让每个查询方法都接收一个连接obect:但这意味着当我尝试在BaseModel类中使用这些方法时,我仍然需要将连接对象紧密地耦合到BaseModel.
>保持原样:这意味着在PHPUnit测试期间,我将不得不重写BaseModel.

无论哪种方式,我觉得我做的不对.我相信我有更好的方法来完成这项工作,我需要你的帮助.谢谢

最佳答案 在
Statics are Death to Testability引用MiškoHevery:

Here is another way of thinking about it. Unit-testing needs seams, seams is where we prevent the execution of normal code path and is how we achieve isolation of the class under test. seams work through polymorphism, we override/implement class/interface and than wire the class under test differently in order to take control of the execution flow. With static methods there is nothing to override. Yes, static methods are easy to call, but if the static method calls another static method there is no way to overrider the called method dependency.

引用Kore Nordmann于Static considered harmful

If you start unit-testing your code you will quickly notice why static dependencies are so bad – because it becomes almost impossible to replace implementations during testing, so that you often end up testing your full framework stack or need to write dozens of helper classes just for the sake of testability. And you would not need that without static dependencies.

TL; DR:如果您想要可测试的代码,请不要使用静态.

关于你的具体情况:

如果您不想重写代码以不使用静态,请考虑在基类上添加查询类的属性,例如:添加类似的东西

public static function setQueryClass($className) {
    static::queryClass = $queryClass;
}

然后通过调用set $className替换所有对StaticSQLQuery的硬编码调用.虽然这仍然有点难看,但它允许您在测试期间用不同的类替换StaticSQLQuery,例如with PHP7 and Anonymous classes你要把它放到你的测试中:

BaseClass::setQueryClass(
    get_class(new class extends StaticSQLQuery {
        public static function init()
        {
            return 'My stub';
        }
    })
);

在PHP7之前,你将不得不对该类进行硬编码:

class StaticSQLQueryMock extends StaticSQLQuery
{
    public static function init()
    {
        return 'My stub';
    }
}

BaseClass::setQueryClass(StaticSQLQueryMock::class);
点赞