Sunday, 5 August 2007
On Good Frameworks forcing Good Things upon us
OK, I admit it's personal. I hate being enforced since my childhood. But I'll try to be objective (as if sentient beings could be objective) and put a couple of reasons behind my emotions.
The whole forcing thing is about awareness. If you are a kid you shouldn't play with fire. That's an enforcement that can save a life. If you are aware of the situation and the consequences of your actions, you need freedom to act effectively. Perhaps you are too self-confident, perhaps you don't know the consequences although you think you do. But you take your chance and perhaps learn something from your failure.
My favourite example is about crossing a street. If you are not very confident, you watch the street lights. Green, you go. But it's not the street light that hits you, it's the car. So, a more confident person would watch for a running car (which might hit you even if you cross with a green light). Now, imagine if I'm forced to cross the street when the green light is on. When some drunk driver drives right on me, I can't stop even if I see him coming, because, you know, I'm forced to move.
Same with frameworks. If I'm forced to do a HelloWorld in a "right" way, all with MVP and interfaces and dependency injections, is it a good framework? Do I have to reinvent a MessageBox so that my open source mocking framework is satisfied?
If there's a good pattern, a framework should encourage, not enforce it. You can make a shortcut of sorts, make it simple. And I'm not saying that the authors of such frameworks deliberately block other ("bad") ways of doing things. But presenting some "enforcement" as a feature is like being proud about something that you can't do (as opposite to "can but don't want to").
Back to "testability forces me to think about good design" -- do you really have to be enforced to think about good design?
Thursday, 2 August 2007
Adventures in test-driven development Part 1, first mistake
So far, everything looks so wise. Until I try to write my first test. It's supposed to be pretty straightforward: just print the word "test". However, when I try to write it, I discover that I even don't know my API! I don't have my ICanvas interface, much less its implementation, I don't have a Print method, and I don't know how to glue these things together.
So, although I already knew that I shouldn't design upfront, somehow I got into this trap again. I've been lucky that I haven't written much code before realizing that.
Now I'm going to do it by the book. Just find the simplest way to print a word and do just that. The really simplest way, it turns out, is to inherit from the PrintDocument class and override the OnPrintPage method. Then use the Graphics object to print stuff. For the moment, I have to forget all the elegant objects I invented, and follow the ugly (but quick) path. I even hardcode the word "test" in my code!
But before I do, I should write the test. Mocking Graphics isn't the simplest thing in the world, but with a little bit of Reflector I produce the following piece of code:
Imports TypeMockA few comments here for those who's not familiar with TypeMock. It creates a Mock object that "waits" till a real object of this type is created, and then "hooks" on it and lets us watch/catch/stub/fake method and property calls to this object. This contrasts to the other frameworks and also manual mocking, where you have to manually create an object which replaces the "real" object. Notice that we are mocking a Graphics object which is created somewhere deep in the System.Drawing.Printing namespace. Since the Microsoft's design is (as always) utterly untestable, we can't feed our own mock object, so our only option is trick the code with the help of TypeMock. So, first we create a mock for Graphics, then we tell it that we expect a call to the DrawString method, and that the first argument should be "test", and the rest can be anything. Same with the SystemFonts object, but we also tell it that it should return a specific value.<TestFixture>Public Class Tests
<Test, VerifyMocks>Sub PrintSimpleText()
Dim graphicsMock = MockManager.Mock(Of Drawing.Graphics)(Constructor.Mocked)
graphicsMock.ExpectCall("DrawString").Args("test", Check.IsAny, Check.IsAny, Check.IsAny, Check.IsAny)
Dim SystemFontsMock = TypeMock.MockManager.Mock(GetType(System.Drawing.SystemFonts))
SystemFontsMock.ExpectGetAlways("DefaultFont", New System.Drawing.Font("Verdana", 8))
Dim TestReport = New Report
TestReport.PrintController = New Drawing.Printing.PreviewPrintController
TestReport.Print()
End Sub
End Class
Now, my production code would be:
I've got a green, I'm happy for today, and I'm particularly ecstatic about having the word "test" hardcoded in my production code.Public Class Report
Inherits PrintDocument
Protected Overrides Sub OnPrintPage(ByVal e As System.Drawing.Printing.PrintPageEventArgs)
e.Graphics.DrawString("test", New Drawing.Font("Verdana", 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)
End Sub
End Class
What I'm not happy about is that ever since I upgraded to TypeMock version4, my Zanebug GUI won't run with the TypeMock runner. So, I had to switch back to NUnit. I don't know about their engines, but I feel quite uncomfortable with the NUnit GUI. OK, it's personal.
What's next? The next useful feature seems to be the ability to print any text we want, not just the word "test". This is going to be the topic of the next post.
Adventures in test-driven development, Introduction
My toolbox:
Visual Basic 2008 Express Edition (I'm going to miss the TestDriven.Net add-in a lot!)
Adaptev's Unit testing framework and Zanebug (I don't know why I prefer it over NUnit)
TypeMock -- it saves a lot of testing efforts
RhinoMocks -- I was told that it "enforces good design", so, although I don't like being enforced, I decided to try it and see the design it enforced.
Now, let's start!