使用 new 运算符重构代码以使其更具可测试性
我有以下代码并尝试对其进行单元测试: <代码>
公共重写 IRenderable GetRenderable()
{
var val = SomeCalculationUsingClassMemberVariables();
返回新的 EquationRenderable(val);
} 。
看来我想在这里使用一个工厂,这样我就可以将 IRenderable 的创建与此类分开 问题是我有许多这样的类,它们创建了以不同方式构造的不同 IRenderable,因此我需要为每个类实现一个新的工厂方法。解决这个问题的最佳方法是什么?
I have the following code and am trying to unit test it:
public override IRenderable GetRenderable()
{
var val = SomeCalculationUsingClassMemberVariables();
return new EquationRenderable(val);
}
It seems like I want to use a factory here so I can separate the creation of the IRenderable from this class. The problem is that I have many of these classes that create different IRenderables that are constructed in different ways, so I would need to implement a new factory method for each one. What is the best way to solve this problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好问题。
首先,由于 DI 容器没有以“正确”的方式使用或者设计可以改进,所以在任何地方都想使用 AbstractFactories 的感觉有点难闻。
但有时我也遇到过这个问题。我看到以下内容:
注入已经被提及,所以我不会重复。我更喜欢 Java,所以请原谅一些语法错误。
测试“新”的输出
如果“新”创建的实例是域对象而不是服务,我经常使用它。因为它是直接在方法中返回的,所以我可以用我的测试来测试直接输出。
存根“new”本身的调用
只有当您以某种方式将其作为返回值时,才可以测试上面的直接输出。如果代码的“副作用”是间接输出(您无法通过返回值直接感知),事情会变得更加复杂。如果是这样,我经常提取新创造的方法,然后在我的测试中控制它。这很糟糕,我更多地使用它来保证测试的安全,并在以后开始更多的重构(DI 和工厂)。我有时会在遗留代码中执行此操作,其中直接使用“新”创建服务,并且在没有测试的情况下重构为 DI 风险太大。
我知道,这个例子有点矫枉过正,有点毫无意义,它只是为了描述这个想法。我确信上面的内容可以通过 C# 的模拟框架来简化。无论如何,在这里测试返回值直接输出是更简单、更好的方法。
也许你有更详细的例子?
Good question.
First of all, feeling tempted to use AbstractFactories everywhere smells a bit as DI container is not used the "right" way or design could be improved.
But sometimes I've also come across this problem. I see following:
Injection got mentioned already so I won't repeat. I am more into Java so please excuse some syntax errors.
Test the output of 'new'
I often use this, if the 'new' created instances are domain-objects and not services. Because it is returned directly in method I can test the direct output with my test.
Stub the call of 'new' itself
Testing direct output from above is only possible if you somehow get it as return value. Things get more complicated if the "sideeffect" of your code are indirect outputs, which you can't sense directly by the return value. If so I often extract-method of the new-creation and then have it under control in my test. This is yucky and I more use it to go safe with my test and start more refactoring later (DI and factories). I sometimes do this in legacy code where services are created with 'new' directly and refactoring to DI is too risky without tests.
I know, the example is overkill and a bit senseless, it is just for describing the idea. I am sure above could be shortcutted with mocking-frameworks for C#. Anyway testing the return-value direct output is more trivial and better approach here.
Maybe you have a more detailed example?
根据具体 IRenderable 构造函数的一致性,您可以使用以下模式进行工厂创建
,或者如果您有许多不同的构造函数,您可以使用 params 关键字传递任意数量的参数
以便能够对参数进行某种运行时检查您在调用 Activator.CreateInstance 之前使用此代码
depending on the uniformity of your concrete IRenderable constructors you can use the following pattern for factory creating
or if you have many different constructors you can use the params keyword to pass arbitrary amounts of arguments
To be able to do some kind of runtime check of the arguments you use this code before calling the Activator.CreateInstance
更好的方法可能是简单地按原样对代码进行单元测试,而不是重构它。从技术上讲,这可以通过使用合适的模拟工具来完成,例如 TypeMock Isolator 或 Microsoft Moles(还有第三个,我现在不记得了)。
A better way may be to simply unit test the code as is instead of refactoring it. Technically, this can be done by using a suitable mocking tool such as TypeMock Isolator or Microsoft Moles (there is a third one which I don't remember now).