|
From: Mike R. <mik...@th...> - 2004-01-08 13:40:22
|
Hi all,
Say you have the following:
class Foo
{
public Foo(int x) { .. }
public Sheep calculateSheep() { .. }
}
class Bar
{
public Bar(Foo foo) { .. }
}
class BarTest
{
[Test]
public void DoesSomethingWithFoo()
{
DynamicMock mockFoo = new DynamicMock(typeof(Foo));
Foo aFoo = (Foo) mockFoo.MockInstance;
Bar aBar = new Bar(aFoo);
}
}
As NMock stands right now though, this won't work because Foo doesn't
have an empty constructor. The answer to this so far has been to either:
(a) Interface/Impl separate Foo
(b) Add an empty constructor to Foo
With (a), we would therefore get:
interface IFoo
{
Sheep calculateSheep() { .. }
}
class Foo : IFoo { .. }
class Bar
{
public Bar(IFoo foo) { .. }
}
I/I separation fans like this because it means a lot of I/I separation
happens. People that don't like introducing interfaces when there's only
one implementation have a big problem with it though.
With (b), we end up with a bunch of constructors in our project that
only exist for testing. This is a bad thing if you're using IoC(3)
principles.
So, Jim Arnold made a change the other day to our internal version of
NMock so that you can do the following (call this option (c) )
class BarTest
{
[Test]
public void DoesSomethingWithFoo()
{
DynamicMock mockFoo = new DynamicMock(typeof(Foo));
Foo aFoo = (Foo) mockFoo.GetInstance(2); /// Note the new method
on DynamicMock
Bar aBar = new Bar(aFoo);
}
}
In other words, you can mock classes with non-empty constructors by
passing in some constructor values, and constructor matching happens
against the class being mocked.
I would like to suggest an alternative (d) though which is quite like
option (a) as follows: if you call GetInstance() with no arguments, then
any constructor is used on the class being mocked; null or zero values
are passed in as relevant and any exceptions are caught and swallowed.
With such a mock instance it is invalid to pass calls to the mock
instance through to the parent class.
Why? Because this would allow us to use the signature of the class,
without having to worry about any state in the mocked class. Effectively
it does automatically exactly what we would do manually by extracting an
interface.
Any thoughts?
Mike
|