我正在尝试制作可以进行单元测试的第一个项目.令人惊讶的是,我必须重新编写一些恶意编码风格的大脑.
这篇文章让我得到了Singletons are pathological liars的关注
我不是试图激进,但我习惯了一件神器,我不知道怎么能摆脱它
例:
initialization ModelFactory.RegisterFactoryMethod('standard.contasmovimento',function(AParam: Variant) : TModel begin result := TModelContasMovimento.Create(AParam); end); end.
ModelFactory是一个单例,在其单元上定义,是该单元的uses子句的一部分.
在我的MVP结构中,我在其自己的单元(1个1级单元)中定义了每个模型,视图和演示者.根据每个项目的需要,可以使用所有这些单元.因此,我将其用作零件目录,根据项目我将单元添加到项目中,它会自动注册并准备好从工厂使用.
为了解决单例问题我正在考虑将它们移动到框架类,因此我可以在一个点创建对象,然后可以使用依赖注入来传递框架对象.所有的工厂和其他环境都坐在那里:
TMyFramework = class FModelFactory: IModelFactory; FViewFactory: IViewFactory; FPresenterFactory: IPresenterFactory; property ModeFactory: IModelFactory read FModelFactory; ...
我的意思是以一种我可以在测试单元中模拟它们的方式移除单身人士.随着单身人士的到位,我无法轻易将其移除以进行测试.
但这将使我放松每个单元的自动初始化,我依靠它来添加单元.我不想手动创建可用类的列表.
有没有办法解决这种情况?
解决方法
为了让单元测试在没有完全重写你所拥有的所有单身的情况下起步,我发现只需添加自由和重新创建单身的能力通常足以让你开始.
假设单例在初始化部分实例化(禁止那些.它们是任何单元测试的祸根.去单独的注册和初始化单元.),你可以简单地向接口部分添加两个过程.如果您不希望普通项目中的其他单元使用它们,请将它们置于条件定义之间:
{$IFDEF DUNIT} procedure InstantiateMySingleton; procedure FreeMySingleton; {$ENDIF}
将您现在在初始化和完成部分中的代码移动到这些过程的实现,并从初始化和完成中调用它们.
procedure InstantiateMySingleton; begin // ... end; procedure FreeMySingleton; begin // ... end; initialization InstantiateMySingleton; finalization FreeMySingleton;
完成此操作后,您可以在单元测试的设置和拆卸方法中开始使用InstantiateMySingleton和FreeMySingleton.
您剩下要做的就是确保创建和销毁单例不会泄漏内存,并且每次都可以使用相同的功能结果重复实现.我发现有一件事有助于确保这是使用GUI运行器并运行整个测试套件两次(当然不退出GUI!).如果测试在第一次运行时成功并在第二次运行时失败,则在初始化或完成单例时遇到问题.