c++ 重构Singletons/Globals以使用Dependency Injection进行单元测试

oug3syen  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(174)

我正在开发一个大型代码库,它广泛使用了Singleton模式和一些Globals。我刚刚开始尝试编写一些单元测试,但是单例和全局测试给我带来了很多问题,在阅读了之后,依赖注入似乎是一条正确的道路。
前面的重构任务是非常艰巨的,我正在努力找出最好的方法。据我所知,基本的想法是这样的:

foo()
{
    GraphicsCache::Instance()->GetMyImage();
    // do stuff
}

然后把它变成这样

foo(GraphicsCache *Cache)
{
    Cache->GetMyImage();
    // do stuff
}

这样,我就可以对这些对象进行模拟,并在测试中使用这些模拟。但是有很多这种类型的对象(事件记录器,网络对象,其他缓存等),这几乎意味着我最终会到处传递很多对象,并最终会到处添加很多代码。我的想法对吗?有没有更好的方法来做到这一点?
我的一个想法是有一个单一的对象,它是所有这些当前全局对象的容器,我所要做的就是传递一个引用,但这感觉不对,因为大多数地方不需要访问每个全局对象,只是一个子集。

vzgqcmou

vzgqcmou1#

你应该按你的建议去做,把东西传来传去才是正确的方法。你也可以使用工厂。是的,你最终会添加很多代码,但这是值得的。
不要创建一个“package”对象来传递,从我所看到的来看,它会产生与全局变量完全相同的问题,你不能告诉你的对象真正依赖于什么,因为所有的东西都被传递给了它们。
如果你真的没有那么多时间,或者它可能因为其他原因而不起作用(比如你的经理对此不满意),你也可以创建专用的工厂,并更改工厂从测试中创建的对象。
你可以阅读更多关于它的信息,它被称为Interface Segregation Principle
简单地说,这个原则指出**一个类不应该依赖于它不使用的函数。

piztneat

piztneat2#

我是从C#的Angular 来回答这个问题的,但它应该同样适用于C++。对象肯定比单例好,但是对于真正的横切关注点(即,日志记录等),您可能需要考虑将这些单例修改为AmbientContext模式。它基本上是一个类固醇的单例,但您可以在应用程序/测试启动时将其示例化为您选择的接口实现。这将使记录器完全可测试,同时不会导致您必须将它们注入到所有内容中。
环境上下文也可以作为一个临时的中间地带,允许测试,以避免在进行中重构所有这些单例。

相关问题