Sunday, 5 August 2007

On Good Frameworks forcing Good Things upon us

Every now and then I read people say things like "testability forces me to think about good design", or, "This framework is good/bad because it does/doesn't enforce good design practices". Although I usually try my best to respect other people's views, such things literally drive me mad.

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

Now that I'm starting to write my first test, I discover that I have already thought well about my future design. I made some key decisions as well. For example, I decided to decouple from the Graphics class. I also decided not to inherit from the PrintDocument class (a direct consequence of my first decision). Instead, I decided to provide an interface, let's call it ICanvas, and redirect all calls to Graphics somehow. This would allow me to avoid testability issues with Graphics (even if I mock it with TypeMock, internally it depends on other objects, so I have to dig in and specifically mock a couple of calls), and also it would allow me to substitute it for other outputs later, so that in theory I'll be able to print to PDF, Word, HTML etc., and the developers could add other outputs.

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 TypeMock

<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

A 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.

Now, my production code would be:

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

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.

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

Being a novice to TDD, I decided to start some sort of a diary about re-making of FreshReports using things I learned recently about the TDD process. Hopefully it'll help somebody to get started.

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!