当我为特定类型的对象编写测试时,例如Forms或UserControls等UI元素,我经常发现自己正在改变我的TDD模式;我定义并布局表单的控件,提供一个“框架”,然后开始编写行为测试(数据绑定/“解除绑定”,显示模式行为等),而不是先进行测试。这样做,我发现自己正在与非公众成员打交道。我也遇到了与其他行为方法相同的担忧;在担心其他方法及其行为的使用之前,我可能想关注并练习由另一种方法调用的某个私人助手的逻辑。对我来说,把所有东西都公开(有时是虚拟的)只是为了能够单元测试一切都是一种气味;我不希望其他对象能够调用助手,或者直接访问文本框;但是我需要知道帮助程序完成它的工作,并且文本框在窗体加载时获得它的值。测试“代理”;好的TDD或代码味道?
我前段时间得出的解决方案是为实际测试的对象创建一个“测试代理”。代理派生自被测对象,并且不会隐藏或覆盖任何行为,但它确实提供内部可见的获取器,设置器和/或调用被测对象的非公共成员的方法,允许我告诉对象执行某些动作,然后我可以查看结果,而不要求测试也依赖于对象内的正确集成,或者仅仅为了测试目的而使该方法或某些其他感兴趣的成员公开于生产代码中。
优点我看:你是否希望有一个单元测试或不
- 议员的知名度没有被确定。
- 对测试中的对象进行更好的控制可以实现更灵活和可扩展的测试。
缺点我看到:
- 类数量的增加,一个额外的水平,只是开发用于测试目的。
- 必须小心,不能以某种方式结束了在生产中使用的测试代码代理(使构造函数或整个班级内部通常的伎俩)
- 没有一个“纯粹”的单元测试,你是,在一定程度上,取决于代理和实际被测对象之间的集成。
的问题是,这是建筑师的单元测试有效的办法,还是确实的事实,我必须这样做指示与代码或测试策略有问题?
“私人助手”是一种方法还是一类?如果它是一个班级,那么它的方法应该是公开的,因此可以从外部进行测试 - 这太棒了。如果是一种方法,可以考虑把它变成一个班,从而减少到以前的情况。 – 2011-01-05 18:41:00
好的建议,但不会总是有效。作为一个更具体的例子,我为表单挑选的一个常见模式是实现一个Bind()方法,其作用是获取一些数据对象并填充表单或嵌套控件中包含的控件。这种方法需要操作其他非公共成员(嵌套控件),它只对它所写的一种形式有价值,并且它是系列中正确初始化表单的一个步骤,所以我不希望它被调用直接通过生产代码。 – KeithS 2011-01-05 18:54:59
我错过了什么吗?为了代理你的班级,你是否需要保护私人会员?所以你的测试策略迫使你让你的成员比你想要的更容易访问? – David 2011-03-10 11:22:39