当我为某些类型的对象编写测试时,比如Forms或UserControls之类的UI元素,我经常会发现自己正在改变我的TDD模式;而不是先测试,我定义并布置窗体的控件,提供“骨架”,然后开始编写行为测试
对我来说,让一切公开(有时是虚拟的)只是为了能够对所有东西进行单元测试就是一种气味;我不希望其他对象能够调用帮助程序,或直接访问文本框;但我需要知道帮助器完成它的工作,文本框在表单加载时获取其值.
我前段时间提到的解决方案是为测试中的实际对象创建一个“测试代理”.代理派生于被测对象,并不隐藏或覆盖任何行为,但它确实提供了内部可见的getter,setter和/或方法,可以调用被测对象的非公共成员,允许我告诉对象执行某些操作,然后我可以查看结果,而不要求测试依赖于对象内的正确集成,或者只是为了测试目的而在生产代码中公开该方法或其他一些感兴趣的成员.
我看到的优点:
>会员的可见度不取决于您是否需要进行单元测试.
>更好地控制在测试中可以对对象执行的操作,从而实现更灵活和可扩展的测试.
我看到的缺点:
>类计数增加,只为测试目的而开发一个额外的级别.
>必须注意不要以某种方式最终在生产代码中使用测试代理(使构造函数或整个类内部通常都有效)
>在某种程度上,不是“纯”单元测试,而是依赖于代理和被测对象之间的集成.
问题是,这是构建单元测试的有效方法,还是我必须这样做的事实表明代码或测试策略存在问题?
我对这种模式的第一反应是你不再强调TDD中的’D’.您的代码已经过测试,但这些测试并没有推动您的设计,因此您最终得到的代码与您先编写测试时的结构不同.具有比必要的更难以访问的私有状态的结构.一般来说,我认为如果你不能使用公共接口测试你的类的行为,那么你要么编写一个没有意义的测试(测试实现细节),要么你的公共接口设计很差.但是,如果您正在使用视图类,这会变得有点复杂,因为您要通过视图进行“公共”输入和输出,而这些输入和输出您要测试但不一定使用此视图组件对代码进行公开.在这种情况下,我认为让测试访问该用户界面是有意义的;通过将那些通常的私有属性暴露给测试(您的代理是一个选项而其他可能根据您使用的语言可用)或者通过编写某种形式的功能测试来驱动UI(同样可用的工具取决于您的环境) ).