This is a republished blog post from 2007. You can tell it's old because the tests were in NUnit instead of xUnit.net. :)
I've demonstrated this a few times in presentations, and someone will inevitably ask for more information. Truth is, I don't remember when I came up with it, or where I might've been inspired for it. I should say up front that I don't believe in mock object frameworks (because they encourage white-box protocols), and I don't believe in [SetUp] and [TearDown] (because they hide intention and force the use of fields in test fixtures, which should be strongly discouraged).
An example I was giving yesterday was a user editor in Model-View-Presenter style (what Martin Fowler now calls Supervising Presenter). The user editor presenter needed to talk to two things: the view and the user service. We ended up with a presenter with a constructor signature like this:
public class UserEditorPresenter { public UserEditorPresenter(IUserEditorView view, IUserService service) [...] }
Given my dislike of [SetUp] and [TearDown], that means that each test starts out with code like this:
[Test] public void MyTest() { StubEditorView view = new StubEditorView(); StubUserService service = new StubUserService(); UserEditorPresenter presenter = new UserEditorPresenter(view, service); }
Interestingly, we started with just the view, and then later added the user service. When that happened, it meant we had to change all our tests. No fun.
Since I'm averse to [SetUp], I like this alternative instead:
public class TestableUserEditorPresenter : UserEditorPresenter { public StubEditorView View; public StubUserService Service; private TestableUserEditorPresenter(StubEditorView view, StubUserService service) : base(view, service) { View = view; Service = service; } public static TestableUserEditorPresenter Create() { return new TestableUserEditorPresenter( new StubEditorView(), new StubUserService() ); } }
Now the tests become one-liner initialization:
[Test] public void MyTest() { var presenter = TestableUserEditPresenter.Create(); }
As the needs of the presenter grow, the tests don't need to be modified. It's easy to follow the Create link in your editor to see exactly what is happening during creation (instead of searching for the SetUp method).