简体   繁体   English

没有IoC或依赖注入的模拟

[英]Mocking without IoC or Dependency Injection

Is there a way to use mocks or fakes in your unit tests without having to use dependency injection or inversion or control? 有没有办法在单元测试中使用模拟或假货,而无需使用依赖注入或反转或控制?

I found this syntax can be used with TypeMock Isolator ( http://learn.typemock.com/ ). 我发现这种语法可以与TypeMock Isolator( http://learn.typemock.com/ )一起使用。 It is a comercial product though, so I was hoping that other frameworks (such as RhinoMocks) would be introducing such syntax at some stage. 虽然它是一个商业产品,所以我希望其他框架(例如RhinoMocks)会在某个阶段引入这样的语法。

/// Can mock objects WITHOUT DEPENDENCY INJECTION.

var hand = Isolate.Fake.Instance<Hand>();
var mouth = Isolate.Fake.Instance<Mouth>();
Isolate.Swap.NextInstance<Hand>().With(hand);
Isolate.Swap.NextInstance<Mouth>().With(mouth);
...
//notice we're not passing the mocked objects in.
var brain = new Brain();
brain.TouchIron(iron);
...

This is very attractive to me this type of syntax, it all happens automatically. 这对我这种语法非常有吸引力,这一切都是自动发生的。 We can create a brain there with no required dependencies being passed in and the mocking framework will substitute the dependencies automatically for the mock objects. 我们可以在那里创建一个没有传递必需依赖项的大脑,并且模拟框架将自动替换依赖项用于模拟对象。 Any body seen this type of thing anywhere else? 任何身体在其他地方看到过这种类型的东西?

The brain class constructor looks like this now using the above syntax, 大脑类构造函数现在使用上面的语法,

public Brain()
{
    _hand = new Hand();
    _mouth = new Mouth();
}

Whereas the dependency injection example would look like this, 依赖注入示例看起来像这样,

public Brain(IHand hand, IMouth mouth)
{
    _hand = hand;
    _mouth = mouth;
}

Thanks. 谢谢。

If you have a choice, you should almost always expose a constructor to allow dependencies to be injected. 如果您有选择,您应该几乎总是公开构造函数以允许注入依赖项。 You could still keep the convenience constructor (though some would argue that you shouldn't): 您仍然可以保留便利构造函数(尽管有些人认为您不应该这样做):

public Brain() : this(new Hand(), new Mouth()) { }

That said, in addition to Isolator you could check out the latest builds of Pex ( 0.17 ), which include moles that provide a mechanism similar to Isolator's Swap . 也就是说,除了Isolator之外,您还可以查看Pex( 0.17 )的最新版本,其中包括提供类似于Isolator's Swap的机制的鼹鼠

Personally I don't think this is a good thing. 我个人认为这不是一件好事。

To me, DI provides more good than just testability, so it is unreasonable to go from it even if some tool allows doing it. 对我来说,DI提供的不仅仅是可测试性,所以即使某些工具允许这样做也不合理。 See also this question and the first answer to it. 另请参阅此问题及其第一个答案。

AFAIK, TypeMock is the only framework that allows this scenario, and probably will be for a long time. AFAIK,TypeMock是唯一允许这种情况的框架,可能会持续很长时间。 The reason is that it uses a radically different approach to mocking. 原因是它使用了一种截然不同的模拟方法。

All other mocking frameworks use dynamic type creation to do the same thing that you could do in code: extrand and override. 所有其他模拟框架都使用动态类型创建来执行与代码相同的操作:extrand和override。 In this case, manual and dynamic mocks are basically the same thing , because the they rely on being able to extend abstract types. 在这种情况下, 手动和动态模拟基本相同 ,因为它们依赖于能够扩展抽象类型。

TypeMock uses a radically different technique, because it uses the (unmanaged) .NET Profiling API to intercept calls to any type. TypeMock使用完全不同的技术,因为它使用(非托管).NET Profiling API来拦截对任何类型的调用。 This is much harder to implement, so it shouldn't be surprising that it is a commercial undertaking. 这实施起来困难得多,因此它是一项商业活动也就不足为奇了。

In any case, TypeMock vs. the rest of the world is an old and very lively debate. 在任何情况下, TypeMock与世界其他地方的争论都是古老且非常生动的。 Here's one take on it (be sure to also read the comments). 这是一个接受它 (一定要阅读评论)。

Moles , a detour framework that ships with Pex , also allows to do this... but with a different syntax. MolesPex附带的绕行框架,也允许这样做......但语法不同。

MHand.New = (me) => {
    new MHand(me) {
        TouchIronIron = iron => {}
    };       
};

Note that your example is inconsistent. 请注意,您的示例不一致。

Thanks for that. 感谢那。 It has given me heaps to think about. 它给了我很多思考。 I am working on an app that has not been designed for testing and currently does not have unit tests. 我正在开发一个尚未设计用于测试且目前没有单元测试的应用程序。 I think the final solution will be to restructure it gradually, and use Rhino Mocks. 我认为最终的解决方案是逐步重组,并使用Rhino Mocks。 I have used Rhino heaps before, and it has been great. 我之前使用过Rhino堆,它很棒。

I have started to realise that the 'all in' solution is probably the best, ie Rhino will force the restructure to use full Inversion of Control which will force good design decisions. 我已经开始意识到'全进'解决方案可能是最好的,即Rhino将强制重组使用完全控制反转,这将迫使做出良好的设计决策。

Regardless of which mocking framework I use I would be comfortable that I myself could make good design decisions as I have done heaps of work like this before, but others working on the code have not done unit testing before, so the scenario that forces them to use IoC is better. 无论我使用哪种模拟框架,我都会觉得我自己可以做出很好的设计决策,因为我之前已经完成了大量工作,但是其他从事代码工作的人之前没有进行过单元测试,所以强迫他们去使用IoC更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM