Mocking without IoC or Dependency Injection
Is there a way to use mocks or fakes in your unit tests without having 开发者_StackOverflow中文版to use dependency injection or inversion or control?
I found this syntax can be used with 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.
/// 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
.
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. 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. 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. 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. 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. 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.
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. I have used Rhino heaps before, and it has been great.
I have started to realise that the 'all in' solution is probably the best, i.e. Rhino will force the restructure to use full Inversion of Control which will force good design decisions.
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.
精彩评论