情况就是这样:我的课程做得太多了。它主要用于访问配置信息,但它也具有数据库连接。它是作为一个单独实现的,所以这也使单元测试变得困难,因为大多数代码与它紧密耦合。这甚至更成问题,因为它创建了一个导入时间依赖项(我们在Python中这样做),这意味着某些模块必须按特定顺序导入。理想情况下,我想将它分成两个类,并使其成为非单例。
幸运的是,我的雇主已经热心这样一个事实,即这种测试是好的,并且如果它使代码更易于测试,我愿意允许我做出这样的更改。但是,我怀疑他们是否愿意让我花费太多时间。而且我宁愿逐步修复它,而不是试图过于激进。
所以,我在这里看到三个选择:
那我该怎么办?
答案 0 :(得分:5)
如果没有看到您的代码,很难知道,但为什么不按照您的意思去做 - 逐步进行?首先执行步骤1,拆分数据库。
如果那很快就回去,你现在只有一个较小的物体停止成为单身而不是2.所以第2步应该更快。或者在这个阶段,您可能会看到一些其他代码可以从单例中重构。
希望你可以逐步减少单身人士中的内容,直到它消失,而不必在任何一步中缴纳巨额的时间税。
例如,如果配置的各个部分是独立的,那么配置中的一部分或许可以一次单独配置。因此,在重构文件配置时,GUI配置可能会留下单例,还是类似的东西?
答案 1 :(得分:5)
我认为你有望分成两个班级。您可能需要考虑使用工厂根据需要创建数据库上下文/连接。这样,您可以将连接视为根据需要创建/处置的工作单元,而不是在对象的生命周期内保持单个连接。但是YMMV。
至于配置,这是我发现单身人士可能是正确选择的一种情况。我不一定会抛弃它只是因为它很难进行单元测试。但是,您可能需要考虑构建它以实现接口。然后,您可以使用依赖项注入在测试期间提供接口的模拟实例。如果注入的值为null,则构建生产代码以使用单例实例或注入单例实例。或者,您可以构造类以允许通过私有方法重新初始化,并在setup / teardown测试方法中调用它,以确保它具有适合您的测试的配置。我更喜欢前者到后者的实现,但是当我无法直接控制界面时我也使用过它。
逐步进行更改肯定是要走的路。如果可能的话,用测试包装当前的功能,并确保在修改后仍然通过这些测试(当然,不是那些直接处理修改的测试)是确保你不破坏其他代码的好方法
答案 2 :(得分:2)
选项1是我在所有应用程序中执行的操作:配置对象单例和按需创建或注入的数据库对象。
将cofiguration对象作为单身人士一直非常适合我。只有一个配置文件,我总是希望在应用程序启动时读取它。
答案 3 :(得分:2)
请原谅我不知道任何Python的事实,所以我希望任何伪代码都有意义......
我首先将对象分成两部分,以便你的单身人士的责任更小,然后我将剩余的配置单例并将其改为普通的类(就像你要执行你的第二个建议一样) )。
到目前为止,我已经创建了一个新的包装器单例,它公开了配置类的方法:
class ConfigurationWrapper : IConfigurationClass
{
public static property ConfigurationWrapper Instance;
public property IConfigurationClass InnerClass;
public method GetDefaultWindowWidth()
{
return InnerClass.GetDefaultWindowWidth();
}
etc...
}
现在应用程序做的第一件事就是将一个ConfigurationClass实例注入包装器。
ConfigurationClass config = new ConfigurationClass()
ConfigurationWrapper.Instance.InnerClass = config;
最后,您可以将当前依赖单例的类移动到包装器单例(应该是快速查找和替换)。现在,您可以一次转换一个类,通过它们的构造函数获取配置对象以完成第2阶段。任何您没有时间做的事情都可以使用包装器单例。一旦你将它们全部移动,就可以摆脱包装。
另一方面,你可以忽略用法的重构,只需将一个模拟的配置类注入到单例包装器中进行测试 - 基本上是一个穷人的依赖注入。