Friday 31 August 2007

Out Of Memory.. again!

Yesterday I plugged my quick-n-dirty Gallery module into DotNetNuke (I developed the most I could as a separate User control), and Bang! I've got this weird OutOfMemoryException. Now, I'm pretty sure that even the DotNetbeast can't eat all my virtual memory, so it should have been something else. Now the funny part: a quick Googling revealed that some poor user already have had this problem (and solved it by himself). And guess what: it was me! At least nobody else posted a message about it with a full stack trace. But I've got a pretty good reason to think that this particular error is related to me in some esoteric way.

Maybe it's a sign that I forgot something very important? Or I remember too much?

Anyway, for those who are interested in solving the problem. I've been using an ObjectDataSource (yes I'm a script kiddie), and it was referring to a class in my DAL project. It worked fine in a standalone project, but when I registered it in DotNetNuke and moved the DAL assembly to the bin, the error occurred. Acually, it has nothing to do with memory. The name of my class was written without the assembly name. Once I added it, everything went OK.

The stack trace is below. As you can see, there's not a line of my code, so there's no chance I could even debug it. Also, the exception happens at the _GetType method, which is most probably native, so perhaps they just throw an OutOfMemoryException then they don't know what's just happened.

So, if you get an OutOfMemoryException when doing some reflection, don't get scared, just double check your type names and make sure they are fully qualified.

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Reflection.Assembly._GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at System.Reflection.Assembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)
at System.Web.Compilation.CompilationUtil.GetTypeFromAssemblies(AssemblyCollection assembliesCollection, String typeName, Boolean ignoreCase)
at System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)
at System.Web.UI.WebControls.ObjectDataSourceView.GetType(String typeName)
at System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)
at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)
at System.Web.UI.WebControls.DataBoundControl.PerformSelect()
at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()
at System.Web.UI.WebControls.FormView.DataBind()
at System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound()
at System.Web.UI.WebControls.FormView.EnsureDataBound()
at System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls()
at System.Web.UI.Control.EnsureChildControls()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Control.PreRenderRecursiveInternal()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
--- End of inner exception stack trace ---

Thursday 30 August 2007

FreshReports: elements and sections

In FreshReports, an element is a minimal unit of printed information. Typical elements are text strings and geometry shapes. Elements are organized into sections. A section is a container for elements; each element belongs to one and only one section. A section can provide logical grouping, positioning (for example, a page header section) and, most important, data. A section can have a data source and thus serve as a data provider to its elements.

Most readers are familiar with traditional reporting components, starting with MS Access reports. Using this analogy, our sections correspond to traditional details and group/report headers/footers. However, in traditional reporting we typically have database rows pulled by some inner join query, so the data is essentially flat. FreshReports, on the other hand, uses object graphs as data, so we can have tree-like structure of sections inside other sections.

FreshReports have a notion of "design time" or "template" section. This is essentially the section definition. Think of it as object representation of the section definition you see in the designer. At runtime, it generates one or several identical clones, named "runtime sections" (or sometimes "detail sections"), according to its data source. This data source corresponds to a table or query result in the traditional reporting scenario, while the DataItem property corresponds to a database row. Individual elements display properties of the DataItem. Note that an element can display several property values mixed with text (the syntax is very close to that of MS Access).

Sections can be broken between pages in 3 different ways, according to the KeepTogether property. The first way is no limitation. If some elements don't fit on this page, they go to the next. At this point, it's not very useful: these elements are going to be printed not at the top of the page but at the same shift from the top of the section. But anyway a typical section is a row of elements, so they won't break to the next page. A more useful scenario is when a section contains some elements and another section. But anyway this is going to work properly only when I implement pushing -- this is when some elements "push" others when they grow.

The second possibility is to keep each runtime section together. And the last is to keep the whole section (all its clones) on one page.

At some point it's going to turn into a set of customizable rules (for example, you'll be able to keep several sections on one page -- useful for table headers).

Note that the features described here are scheduled for the 0.5.1 release.

Monday 27 August 2007

FreshReports 0.5 is out

I've just uploaded the binaries (together with a small sample) to SourceForge. This thing can't do much yet, but it's something I'm very proud of. I managed to build it very quickly, and although design is not perfect, it's just because some important features are ahead (most notably, paging support), and the design waits to be driven by them.

So far, it can print just simple data. Stuff like "[Name]' age is [Age]". Note that this is already ahead of the report engines I've seen: we have two properties in one data element! Note also that I don't use curly brackets. I'm trying to make it as simple as it can be.

If you need to print the object itself, rather than its property, use an empty property name, like this: "This is []". It actually uses the object's ToString() method.

The main usage pattern is like this:
1. Create a Report object.
2. Create the layout (in the future releases it will be possible to load it from an XML file).
3. Add a data source (or several).
4. Print().

Happy printing!

Saturday 25 August 2007

ASP.Net testability.. finally the way it should be!

Now, a year or two ago I decided that all my Web apps should be test-driven too. So, my only option at this point was NUnitAsp (which is great). Basically, it initiated a request, parsed the output, and you could test the properties of your controls. It even allowed you to click buttons or links and process the resulting request. Pretty cool.

There are several problems with this approach. First, these tests are really integration tests. There is no way to mock anything. So, before using any test data, for example, I had to put it into the database. And delete it after each test, making sure it's deleted even if the test fails. Or, when testing the logged in behavior, I had to navigate to the login page, enter the credentials, and click the button. In short, every test setup became huge. Second, The control tree should be traversed manually, meaning that I had to explicitly write things like myLabelTester = New LabelTester("ctl00:Panel1:Label1"). And third, each control type had to have its own tester (which parsed the rendered html), so for a custom control you had to write your own custom tester. Oh, and last time I checked, they had testers for Asp 1.1 version only, and even a DataList tester was missing. You can guess well that after some time I abandoned the idea because writing tests was too painful.

The next thing was Plasma. It also returns the html from your requests and suggests that you parse it (it even doesn't have all the convenience parsers/testers that NUnitAsp has), but there's a big difference. It runs everything in-process. Meaning that whenever I run my favourite test runner, the objects are already there somewhere. I just need to find them.

Basically, I don't want to get an html string from my test and just make sure that it contains "Hello world". I'd like to write something like this:

Dim page As Web.UI.Page = ExecuteRequest("~/Default.aspx")

Assert.AreEqual(1, page.Controls.Count)

Dim label As Web.UI.WebControls.Label = page.FindControl("Label1")

Assert.AreEqual("Hello world", label.Text)

In addition, now I can (theoretically) mock my dependencies. The only problem is that Plasma provides just the WorkerRequest object and the html response body. There's no way I could get to the Page object, not even with some dirty Reflection tricks.

Fortunately, we also have TypeMock, which can do even dirtier. It can set a mock on a type, so that when an object of that type is instantiated, we can get a reference to it, intercept all method and property calls etc.

There are just two minor obstacles left. First, the mock should be created in the AppDomain that is created by Plasma, meaning that I can't just create them in my tests -- I should modify the Plasma code (actually, I don't need Plasma -- there are several examples of hosting Asp.Net out there (see the references at the bottom)). Not much of an obstacle -- I'm going to put all the relevant code just before the request is executed. Second, we don't know the actual type of our page, so we can't mock it. The solution is to mock the HTTPContext object and get the page reference from it at the point it is assigned the Handler property:

System.Web.UI.Page page; //keep the global page variable

internal int ProcessRequest(

string requestFilePath,

string requestPathInfo,

string requestQueryString,

string requestMethod,

List<KeyValuePair<string, string>> requestHeaders,

byte[] requestBody,

out List<KeyValuePair<string, string>> responseHeaders,

out byte[] responseBody) {

WorkerRequest wr = new WorkerRequest(requestFilePath, requestPathInfo,

requestQueryString, requestMethod, requestHeaders, requestBody);

//begin our code

TypeMock.MockManager.Init();

TypeMock.Mock contextMock = TypeMock.MockManager.Mock(typeof (System.Web.HttpContext), TypeMock.Constructor.NotMocked);

contextMock.MockMethodCalled += new TypeMock.MockMethodCalledEventHandler(contextMock_MockMethodCalled);

contextMock.ExpectUnmockedSet("Handler");

//end our code

HttpRuntime.ProcessRequest(wr);

while (!wr.Completed) {

Thread.Sleep(50);

}

responseHeaders = wr.ResponseHeaders;

responseBody = wr.ResponseBody;

return wr.ResponseStatus;

}

void contextMock_MockMethodCalled(object sender, TypeMock.MockMethodCallEventArgs e)

{

if (e.CalledMethodName == "set_Handler") page = (System.Web.UI.Page)e.SentArguments[0];

}



While this is still far from something I could really use in my tests, the main point is already here. By the time we get to the end of the ProcessRequest method, we have a page variable that is really our page, so we can test all its controls, not just the html output.

I think it's worth of a really powerful framework, with Enterprise (I like the word!) features like IHTTPModule testing, built-in authentication and config mocking etc.

Friday 24 August 2007

Another sad DotNetNuke story

After spending a couple of days fighting with the Gallery module's weird errors, I finally decided to write my own module.

And not just that, I finally decided to write my own portal (some day).

Enough is enough. DotNetNuke is great for people who just want to create a portal site. But for developers.. Back then (2 years ago) I thought that software development is painful by nature. So I wasn't surprised when I spent hours trying to figure out that the NullReference exception in my logs is actually a HTTPParse exception. But now I know things can be better. I just put up a site in less than 10 hours that a year ago took about a month for me to create, and after that we spent several months with the designer trying to figure out the layout and trying to apply the correct css classes to the maze of control hierarchies.

So, breaking with DotNetNuke is like breaking with the old hated wife: it's much simpler to leave it as it is, but once you do it, you're breathing fresh air again. I experienced it today (a little) when I started my own module (abandoning the stock Gallery), so I know for sure.

Friday 17 August 2007

Cory Foy: Too many dialog / option levels?

Cory Foy: Too many dialog / option levels?

What's lost, what's gained

I didn't download the full version of VS Orcas since 1) heard that installation is quit painful 2) didn't want to make my system unstable and perhaps 3) didn't need all these super-features and wanted to save my RAM from unwanted guests. For now, I'm coding the new version of FreshReports with the new VB Express.

So far, what I really really miss is the Add-Ons. Namely, the ability to run my tests inside the Visual Studio (TestDriven.Net) and the refactoring support by DevExpress. Also, I still haven't used Ankh (a svn itegration addin) and now I'd try it, but I can't.

What is really nice is the Intellisense. I don't see anything else I could use. But then, I didn't try a WPF app yet.

I switched from Adaptev's Zanebug to MbUnit as my testing environment. What I miss is the GUI that allowed to run only a subset of tests (which might be bad), and to automatically run when the assembly is recompiled. What I gained, supposedly, is a very rich test options (however, haven't tried these yet).

(The MbUnit GUI crashed today without any meaningful message after I applied some cool refactoring to my code. Turned out to be stack overflow. I still have to find a framework that survives this thing.)

I switched (for a while) from TypeMock to Rhino Mocks for my mock framework. What I gained is deeper understanding of my design -- how it should be. In addition, I like the method chaining feature (DSL), and of course the explicit method calls instead of strings when I write the expectations. Sort of, instead of writing ExpectCall(myObject, "DoStuff") I just write myObject.DoStuff in the record stage (I should say that TypeMock also can do that -- but in the paid version). Also, the explicit record/playback syntax is cool (however, I'd rename it to something like expect/verify).

What really disappointed me (twice today) is the failure messages. In TDD, I'm expected to understand immediately what's wrong with my code. Here I couldn't see why my argument expectations fail (had to use the undocumented logging feature), and the worse case, an exception thrown in the middle of the test didn't show up as the source of the failure (instead, it told me that my expectations weren't fulfilled).

So, you can see that my (desktop) life is full of changes -- which is always goood!

Wednesday 15 August 2007

Adventures in test-driven development Part 4: What's next?

I'm not going to write down the whole development story -- it would take months, and I'll never finish the project. So far, we have seen several key principles of test-driven development, as well as some cool design ideas. Let's review them:

1. Test-first: write a test, watch it fail, write the simplest (production) code to make the test pass (you can even hardcore some constants in your code), then refactor in smallest possible steps while keeping the test (and the other tests) pass. This is referred to as Red-Green-Refactor cycle.
2. Test-driven: when your testing is too complex, don't just sigh and accept it. This is a sign that your design can be improved. Let the testing drive your code.
3. YAGNI -- you ain't gonna need it. Instead of implementing a Good Thing just because it is one of the GoF patterns or you've just read it in somebody's blog, whatever makes your tests pass is OK. You see that this method you just wrote is ugly, but wait until the next test drives you in the right direction for refactoring. There's another similar principle, KISS (Keep It Simple, Stupid).
4. Separation of Concerns (SoC) principle -- each object has to have a distinct responsibility. Keep in mind, though, that this is just a clue: whenever you have problems with testability and you don't know what to do, try this or some other design idea (see Dependency Injection below) and see if it simplifies things. The general idea is that you don't apply these patterns or principles blindly, but let your tests decide what to apply.
5. Dependency Injection. We have seen it when we were getting rid of the Graphics dependency. The main idea is that it is very hard to test your class when there's an external dependency involved, such as an SMTP server, local file system, or some unmanaged stuff. So, don't hardcore it into your component, have it "injected" somehow in your production code, and mock it in your test code to make sure that your code interacts correctly with it. Again, the "weakness" of our mock framework dictated this. But this is not just designing for testability -- turns out that it opens a possibility for other reporting options -- exporting to HTML, Word, or maybe projecting onto a Star Wars style transparent screen.

This is no accident that Rhino Mocks forced us for a better design. While TypeMock does its job by applying some sort of black magic, Rhino plays by the .Net rules: overrides virtual methods, extends classes, implements interfaces -- does what you or users of your component would do to extend it.

So, while I'm not going to publish all the details, I'm going to share all my big moves and discoveries, especially TDD-related. The latest source of FreshReports can be found in the SVN repository at SourceForge at https://freshreports.svn.sourceforge.net/svnroot/freshreports/trunk.

Further reading:
TDD Design Starter Kit by Jeremy D. Miller
Achieving And Recognizing Testable Software Designs by Roy Osherove
testdrivendevelopment group on Yahoo

Friday 10 August 2007

Adventures in test-driven development Part 3: Getting Rid Of the Ugly Stuff

As promised, today we are going to get rid of the Graphics dependency. We are also introducing Rhino Mocks into our project. We are going to see how the limitations of this framework are going to make our design better. It might sound as something strange at first, but we'll see how it works. Fortunately, we have written our first test using the all-mighty TypeMock, so we can be sure that nothing breaks.

In order to test our behavior and not print something in the process, we need to mock the Graphics object. However, it is impossible with Rhino, since the class is sealed, or NotInheritable. So, somehow we should eliminate this hardcoded dependency from our class.

Why is this good, apart from testability? First, the Graphics class is a heavy dependency. The sole fact that it is IDisposable tells us that it depends on some unmanaged resources. In addition, it brings a dependency on Win32, which is bad, since we want to develop a universal component. Sure if we want to use our component on Mono or whatever CLR implementation exists, we could find a Graphics analog, but there's no guarantee that these implementations, that are not part of the standards, are implemented the same way.

Also, it carries too much with it that we just don't need. We don't want our main object perform all the low-level work, we want to serve it as a main controller, leaving all individual details to other objects.

Therefore, we are going to introduce a Canvas class, which is going to serve as our main printing device. Immediately, we have two advantages. First, we can provide multiple inheritors of the Canvas class, so, in theory, we can print to PDF, HTML, Word, anything. Second, we are ruling the interface of our Canvas class. Whenever we look at it, we immediately know its responsibilities within our project. We don't have to adapt to the Graphics interface (this is done in the implementation). Since we don't need mysterious stuff that Graphics has, like GetHdc() or FromHwndInternal(), we don't include it as part of our class, so those who use our component won't be tempted to play with it.

Enough said, let's code! Before we even start with our second test, we should do a little redesign.We should move in small steps, running our test after each step. This way we immediately know if we make a wrong step. Remember that RhinoMocks requires that we mock an interface or an inheritable class. The first step is to construct a thin wrapper around the Graphics class, giving out just the methods we need. Let's call it GraphicsCanvas, and let's put it into WinForms namespace. This is the only namespace that is going to reference the System.Drawing assembly, and eventually we are going to extract it into a separate project. Although it seems like adding complexity, actually it makes our design cleaner, since the project itself becomes clean of "the earthly stuff" in some way. For the same reason, I'm going to introduce my analog of the System.Drawing.Point structure.

The first step is, unfortunately, relatively big. We have to write some basic stuff into our new class so that we have something to test. Let's have it:

Namespace WinForms

Public Class GraphicsCanvas

Private _graphics As Drawing.Graphics

Private Sub New()

End Sub

Public Sub New(ByVal graphics As System.Drawing.Graphics)

Me._graphics = graphics

End Sub

Sub DrawString(ByVal text As String, ByVal position As Printing.Point)

Me._graphics.DrawString(text, New Drawing.Font("Verdana", 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)

End Sub

End Class

End Namespace


What do we have here? First, we hold a private variable for our Graphics object. Next, we have a private parameterless constructor, which makes it impossible to construct our class without parameters. Indeed, it cannot exist without the Graphics object. Next, we have a public constructor. I should say here that while the class itself and the constructor can reference the Graphics class, all other public methods shouldn't, since we are going to convert them into an interface later. So, the last is our first printing method. The least we should provide for printing is the text and its location. In fact, it's about 90% of our needs, or close to that.

Now, let's figure out our testing strategy. The way Rhino Mocks, as well as most other mock frameworks, work is quite different from TypeMock. TypeMock places a sort of hook on a class before the concrete object is created, so that when it is created, some method calls can be intercepted. So, it's fine that the object itself is created somewhere in our code. Just like the Graphics object, which is created somewhere deep in the framework. On the other hand, a Rhino Mocks mock should be created explicitly in the test. That forces us to redesign our code, so that we could somehow feed the mock object into our production code. This is done via constructor arguments, property setters, or method parameters. This procedure is generally called "dependency injection".

In our case, each page corresponds to a separate Graphics object, so it makes sense that we provide a separate GraphicsCanvas object for each page. So, the first refactoring is to extract the call to DrawString() to a separate method:

Protected Overrides Sub OnPrintPage(ByVal e As System.Drawing.Printing.PrintPageEventArgs)

Me.PrintCurrentPage(e.Graphics)

End Sub


Sub PrintCurrentPage(ByVal graphics As System.Drawing.Graphics)

For Each section In Me.Sections.Values

For Each element In section.Elements.Values

graphics.DrawString(CType(element, Elements.LabelElement).Text, New Drawing.Font("Verdana", 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)

Next

Next

End Sub

(Remember to run our first test each time we do some refactoring)

In our second test, we are not going to call the Report.Print() method, since there's no way to inject the Canvas dependency. Instead, we'll call the PrintCurrentPage, but only after we figure out how to call it. So, this method should take our wrapper as an argument. The next version looks like this:

Protected Overrides Sub OnPrintPage(ByVal e As System.Drawing.Printing.PrintPageEventArgs)

Dim canvas = New WinForms.GraphicsCanvas(e.Graphics)

Me.PrintCurrentPage(canvas)

End Sub

Sub PrintCurrentPage(ByVal canvas As WinForms.GraphicsCanvas)

For Each section In Me.Sections.Values

For Each element In section.Elements.Values

Dim Text = CType(element, Elements.LabelElement).Text

canvas.DrawString(Text, New Fresh.Printing.Point)

Next

Next

End Sub

But now that we try to write our test, we have a problem. Since our GraphicsCanvas object can't be created without a Graphics object, so can't the corresponding mock. We imposed this limitation on ourselves when we added a private parameterless constructor to our class. We could remove it now, but it would be a bad idea. Instead, let's get our design driven by this limitation. We'll see that it's for the good.

What are the requirements for the type of the canvas argument? First, it should allow us to pass our GraphicsCanvas object, so it should be a base class. Second, it should be mockable. In addition, it should provide our base functionality (the DrawString method) without implementing it (so the method should be abstract, or MustOverride). So, it's either an abstract class or an interface. Typically, such things are done with interfaces. Perhaps historically mock frameworks could work with interfaces but not with abstract classes. For me, an interface is some common functionality among unrelated classes (like IDisposable), whereas an abstract class is a conceptual common ground, like Shape for all geometrical shapes.

So, let's shoot our Canvas class:

Namespace Printing

Public MustInherit Class Canvas

MustOverride Sub DrawString(ByVal text As String, ByVal position As Point)

End Class


End Namespace

Next, we just modify or GraphicsCanvas class so that it inherits from Canvas. And let the PrintCurrentPage accept a Canvas object as its argument:
Sub PrintCurrentPage(ByVal canvas As Printing.Canvas)
So, did it make our design better? First, we have greater control over printing. We have extracted our PrintCurrentPage method and now can call it directly. This is a big step towards being independent from the PrintDocument class by the way. Next, we can print to anything we like, provided we can implement a custom Canvas class. Our main Report object has been relieved from the printing burden, and can concentrate on more important tasks (such as handling the report structure and routing commands to other objects). This is called the Separation of Responsibilities (SoC) principle.

Finally, let's see our test:

<Test()> Sub TestWithRhino()

Dim mocks As New MockRepository()

Dim canvasMock = mocks.CreateMock(Of Printing.Canvas)()

Dim TestReport = New Report

Dim TestSection As New Core.Section

TestReport.Sections.Add("", TestSection)

Dim TestElement As New Elements.LabelElement

TestSection.Elements.Add("", TestElement)

TestElement.Text = "test"

Using mocks.Record

canvasMock.DrawString("", New Printing.Point()) 'we can provide any arguments here

LastCall.Constraints(Rhino.Mocks.Constraints.Text.Like("test"), New Rhino.Mocks.Constraints.Anything)

End Using

Using mocks.Playback

TestReport.PrintCurrentPage(canvasMock)

End Using

End Sub

First goes some preparation. Next we have a Using mocks.Record statement -- it's a first part of the Record-Replay pattern, where we first write down what method calls we expect, what arguments should be there, and which results should the methods return. In our case, the first line states that we should call the DrawString method. The arguments are irrelevant here, but without them the code won't be compiled. The second line tells us that the first argument should be equal to our test string, and the second can be anything.

Last, we have a Playback block where we put our tested method.

Our test actually verifies that the appropriate call is made to the Canvas object. It doesn't verify that the string is actually printed. This is where Rhino Mocks can't help us. However, we can easily write a separate test (using TypeMock) for it. Since we have two separate objects, we can test them independently. We can do all kinds of tests verifying that DrawString is invoked correctly, and only one test verifying that it actually prints something. When we have other Canvas objects, we'll have to make one test for each object, instead of testing all possible report layouts and data with each canvas. That's what the term unit testing is about.

Another thing that's not tested here is that calling the Print() method actually calls the PrintCurrentPage method. So far, we have our first test to verify it, but this is an indication that this piece has to be refactored as well. I guess I'll be making a separate class ReportPrinter that inherits from PrintDocument and manages the interaction with the actual printing and previewing (it can even be used at design-time in a form), and our Report class will be completely ignorant of these implementation details. However, I'll wait till I implement paging and let my tests drive my design.

Sunday 5 August 2007

Adventures in test-driven development part 2: Getting a Meaningful Result

Last time we forced out component to print a word and satisfy out first test. However, we didn't finish the proper TDD cycle: red-green-refactor. So, how can we refactor our code so that it would become a sample of perfect design?

I'm tempted to eliminate the ugly Graphics dependency that's making our code hard to test (even with TypeMock). But after reading some posts on Behavior Driven Development, I feel that I should focus on the main part of our component -- the customer who's using it.

So, I'll start with a user story. Since I'm the author, I'm trying to figure out what would a client want. Something like that:

1. I want to create simple units (called Elements) that represent a single printed unit, like a string or a line, so that a client could add, remove, and move around these elements at her will.
2. I want to organize these elements into containers (called Sections), so that a client could easily think in terms of data records (corresponding to objects or, God forbid, database rows). So, the sections would allow her to group elements in terms of data (single section corresponding to a single data source object) or presentation (page headers/footers).
3. I want to attach unique IDs to all elements and sections so that the client could easily identify each element, at least within a section.

There is another problem with my test. I didn't put the text "test" that's being printed. So, the test actually tests that the word "test" is printed always. This is clearly not my intent, so I should rewrite it. Remember that it should fail, so just to make sure I change the expected word "test" to "test2".

I'm going to name my first element class "LabelElement", since its behavior is close to that of a label. I'm going to add a Sections property to my Report class to hold the list of sections. Same with the Elements property for the Section class. Both properties are going to of be respective generic Dictionary types. It seems like I'm making a lot of design decisions even before writing the test, but I need that to make it compile.

So, my new test code is

<Test(), VerifyMocks()> Sub PrintSimpleText()

Dim graphicsMock = MockManager.Mock(Of Drawing.Graphics)(Constructor.Mocked)

graphicsMock.ExpectCall("DrawString").Args("test2", 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

Dim TestSection As New Core.Section

TestReport.Sections.Add("", TestSection) 'we'll use the first argument for the ID, let's just have an empty string here for now

Dim TestElement As New Elements.LabelElement

TestSection.Elements.Add("", TestElement)

TestElement.Text = "test2"

TestReport.PrintController = New Drawing.Printing.PreviewPrintController

TestReport.Print()

End Sub

Of course, my test fails. It prints "test" instead of "test2". So, for the Green phase I just shamelessly change the hardcoded value to "test2". Then I get to the Refactor stage, and the code becomes something like this:

Protected Overrides Sub OnPrintPage(ByVal e As System.Drawing.Printing.PrintPageEventArgs)

For Each section In Me.Sections.Values

For Each element In section.Elements.Values

e.Graphics.DrawString(CType(element, Elements.LabelElement).Text, New Drawing.Font("Verdana", 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)

Next

Next

End Sub

You can see that we actually achieved more than we intended. We can print several elements now -- all elements that are added to the Report. While we shouldn't add more than one feature at a time usually, this one came almost as a side effect -- I should have printed only the first element of the first section, but it turned out that the code is simpler this way.

Next time we are going to make a huge refactoring, since it's going to make our test-driven life a lot easier.

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!