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.
2 comments:
Good Luck with the testing.
You could post a request in the TypeMock forums about the Zanebug GUI - I am sure that they will help.
Tip: use the [VerifyMocks] attribute and then leave out the MockManager.Init and MockManager.Verify
Thanks for the tip, Eli!
As for Zanebug, I guess I should gather some more information. I've got a record in my Fusion log, saying that something was looking for TypeMock, Version=0.29797.26996.26478, but then I've got all sorts of things there. In VS 2005 I used TestDriven.Net, and TypeMock worked fine. But with Orcas, I downloaded the Express edition, so I don't have the Add-in luxury.
Post a Comment