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).
Maybe a more generic approach would be using IoC Dependency Resolver container for unit tests.. less code to write, IMO.
Posted by: Konstantin Tarkus | June 02, 2011 at 16:44
I like to use a Fluent Builder to solve the same problem.
Posted by: Bradley T. Landis | June 03, 2011 at 05:01
I don't get the point of this. You're messing up the inheritance hierarchy just to get around writing a few lines of code in tests? We already have a pattern for reusing code: a method!
public UserEditorPresenter GetUserEditorPresenter()
{
return new UserEditorPresenter(
new StubEditorView(),
new StubUserService()
);
}
Posted by: Ryan | June 03, 2011 at 08:47
And then how will I get access to the stubs, which will be necessary in the assertions?
Posted by: Brad Wilson | June 03, 2011 at 09:51
Some people like to use IoC in unit tests. I'm not one of them. I find that it's even more noise than my example, for no appreciable benefit. The major benefit of an IoC container in production code is the recursive dependency resolution behavior, something which you do not need or want in a unit test.
Posted by: Brad Wilson | June 03, 2011 at 09:52
Doesn't this inheritance thing in unit tests make them less readable? If so, I would avoid sacrificing readability in favor of shortness.
Posted by: Konstantin Tarkus | June 03, 2011 at 14:27
I came to download xUnit only last week for something, and couldn't find a GUI test runner or get VS test integration working! I had to go and use NUnit instead. It might be pants, but at least it's easily runnable :(
Maybe not ;PPosted by: Danny Tuppeny | June 05, 2011 at 14:03
I don't get it either. You said you don't like [Setup] because it makes you create fields, then you did this, and added fields. What advantages does this have over putting it in [Setup]?
Posted by: Danny Tuppeny | June 05, 2011 at 14:07
I don't like fields in NUnit unit tests because it reuses the same object instance for all tests, so it's easy to accidentally reuse field data and pollute your tests with false negatives (or worse, false positives).
Posted by: Brad Wilson | June 05, 2011 at 17:21
I really don't know why you wouldn't have been able to run the GUI runner, since it's included in the download distribution. How did you get it? By downloading from http://xunit.codeplex.com/ ?
Posted by: Brad Wilson | June 05, 2011 at 21:17
I got it via NuGet, but then went to codeplex looking but couldn't find any info on it (I got the impression it had to be used via TestDriven.net or similar)? :(
Posted by: Danny Tuppeny | June 05, 2011 at 22:37
Not sure how well I looked now, since I went to the download page and it says "GUI runner (xunit.gui.exe...)! Doh!
Posted by: Danny Tuppeny | June 05, 2011 at 23:03
Duh, nevermind, I misread your code and thought you'd created a base class that had fields on it. That's what happens when you catch up on your RSS while you're falling asleep! ;(
Posted by: Danny Tuppeny | June 05, 2011 at 23:04
I used to agree until I started using automocking (Structuremap + MoQ). It's very clean and it's a breeze to add dependencies without having to update test classes.
Posted by: tshak | June 06, 2011 at 22:18
I'm leary of recommending auto-mocking containers for newbies, because you can end up hiding bad designs behind it (as with any mocking system). For experienced TDDers, I'm okay with that approach.
Posted by: Brad Wilson | June 07, 2011 at 09:48
So what do you recommend for newbies instead?
Posted by: Ignacio Fuentes | June 21, 2011 at 07:12
Doing everything by hand. It's not a bad idea to understand what you're doing and why before deciding that it's a good thing to automate.
Posted by: Brad Wilson | June 21, 2011 at 10:53
Setup/Teardown will be executed for each test. If you do not faver these methods then you probably do too much tests that do not correlate well in your test fixture. Probably a sign to split up your fixture.
I do not like your approach but it is not necessary when you use Setup/Teardown which prepare your stubs/fakes/mocks. Your approach makes your test just as 'unreadable' as using Setup/Teardown IMHO.
Posted by: Ramon Smits | June 28, 2011 at 04:20