Wednesday, 12 December 2007

TDDing a HelloWorld application

I'm going to write a very simple WinForms application using TDD, and I'm going to refactor it using TDD as well.

As I'm just learning good OOP design, I often don't have any idea as to how to refactor my (already working) code, and how to properly implement separation of concerns. I also don't know how much I have to cover with tests: I tried too little and was lost in refactoring, I tried too much and couldn't change my design without breaking a lot of tests, so I didn't know if everything was still working or not. So, I'm going to apply my new idea of Test Driven Refactoring and hope that it would bring me somewhere.

Here's the story. We have a form with a textbox and a button. I enter "Martin" in the text box, press a button, and a message box saying "Hello Martin" should appear.

Should I apply MVP or MVC here? Probably, but I won't. Folks say, let the tests drive your design, so I'm letting them. But first, I want to make it work as quickly as I can, so I write a simple test using NUnitForms (see below), and I quickly get the following code:


Private Sub HelloButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HelloButton.Click

MessageBox.Show("Hello " & Me.NameTextBox.Text, "Hello")

End Sub


I quickly see that my form is doing too much. It's been created for the purpose of showing the UI elements and reacting to the user input. However, in this code it decides how to greet the user. It decides how to construct the message, and that the messagebox should be shown.


How do I refactor this code? First, let's see the test:


<Test()> Sub PressingTheButtonShowsAMessage()

Dim form = CreateForm()

form.Show()

Dim boxTester As New TextBoxTester("NameTextBox", form)

boxTester.Enter("Martin")

Dim buttonTester As New ButtonTester("HelloButton", form)

ExpectModal("Hello", AddressOf HelloHandler)

buttonTester.Click()

End Sub



Public Sub HelloHandler()

Dim messageBoxTester = New MessageBoxTester("Hello")

Assert.AreEqual("Hello Martin", messageBoxTester.Text, "Invalid message text")

messageBoxTester.ClickOk()

End Sub


Function CreateForm() As Windows.Forms.Form

Return New TestDrivenRefactoring.Form1

End Function


I see that the test's setup phase is too big. In fact, the whole Test Driven Refactoring (TDR for short) process is built around the idea that too much test setup is a code smell. Specifically, we should refactor so that our unit test's setup takes just as much information as required. For example, in this case, all we need to test the message box is the text of the message. So, we should refactor our code into two components: the first, A, passes some object, X, to the second, B, and the second displays a message box. The information is somehow "packed" into X, and our test should be able to create X directly and pass it to B to test it independently of A.

What is X? It should be created using a single string, and it should provide the same string to B. It could be just a string, but another TDR principle states that such intermediate objects should be flexible, so it's best to make it a custom object. Why not an interface? Could be as well an interface, but we have a simple data transfer object here, with no behaviour, so a custom class should be fine. Let's call it PersonData, and let's rename B to MessageBoxService.

Here's our test for the new class:


<Test()> Sub CallingTheShowMessageMethodShowsAMessage()

ExpectModal("Hello", AddressOf HelloHandler)

Dim messenger As New MessageBoxService

Dim message As New Message With {.Text = "Hello Martin"}

messenger.ShowMessage(message)

End Sub


We see that the setup portion contains just enough: the first line is an expectation which is sort of an assert, creating the two objects doesn't count, and the only nontrivial thing is setting the Text property of the Message object. Now we clearly have a messaging component that encapsulates showing a message box and has no other concerns.

But what about the rest of the application? We can refactor our it straightforwardly:

Private Sub HelloButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HelloButton.Click

Dim messenger As New MessageBoxService

Dim message As New Message With {.Text = "Hello " & Me.NameTextBox.Text}

messenger.ShowMessage(Message)

End Sub


Our first, functional test still passes. But now we are unable to test the behaviour independently of the MessageBoxService object. It is more or less fine that we have a hardcoded Message class -- it's just a simple class with no behaviour. But hardcoding the MessageBoxService class is a real problem: at some point we'll want to switch all our message boxes to the new Vista-style dialogs, or provide a custom form, whatever. We'll have to search-replace thru all of our code to change that.

But at this very moment the problem is that we can't test the remaining piece. So, we have to inject a dependency. Now, we don't want hold a reference to the MessageBoxService inside our form class, since we are not sure we'll need it after the refactoring is finished. So, we use a ServiceLocator pattern.

First we introduce the IMessageService interface:

Public Interface IMessageService

Sub ShowMessage(ByVal message As Message)

End Interface


Next, we do something that is considered one of the worst practices: we introduce a global variable:

Module Globals

Public Services As System.ComponentModel.Design.ServiceContainer

End Module


Now we can obtain a reference to our MessageBoxService as simple as

Dim messenger = Services.GetService(GetType(IMessageService))

But of course we should set it to a concrete service somewhere in the setup code, which has nothing to do with our form:

Services.AddService(GetType(IMessageService), New MessageBoxService)

Similarly, in our test we set it to a mock service, and expect a call to its ShowMessage method.

(to be continued)

Tuesday, 13 November 2007

MUMPS language sample

Just discovered this piece of code:
QUE(RTN,DESC,START,ASK) ;
; Queues a job to Taskman with optional user interaction
; Inputs
; RTN : The full routine info to queue
; DESC : The Description for the task
; START : The start date/time (in FM format) for this job
; : If null, uses today's date/time
; ASK : Prompt the user to queue the job?
; : ASK = 0 (don't) or 1 (ask) If null, defaults to 1
; Outputs
; 0 if not tasked, or the Taskman task # if tasked
;
N %,QUE,TIME,I,X,Y,DTOUT,STOP,%DT
N ZTSK,ZTRTN,ZTDESC,ZTIO,ZTDTH
S QUE=0
S RTN=$G(RTN)
S DESC=$G(DESC)
I RTN=""!(DESC="") Q 0
S START=$G(START)
S ASK=$G(ASK)
I ASK="" S ASK=1
I 'ASK S %=1
S STOP=0
I START="" D ;
...
(see this link for the full code)

I was going to add some sarcastic comments but found myself at loss of words..

Saturday, 10 November 2007

Inka (formerly Freshreports) 0.6.1 is out

Well, not many new features in this release. But I decided that adding the Grouping support is worth a separate release. After all, the traditional report engines use this idea of hierarchic data display (as opposed to the master-detail idea). I was surprised myself for how little code I had to add. I guess, my data and structure part is written pretty good (I certainly can't say this about my layout engine).

The bad news is that you have to group your records yourself. The good news is that with Linq it is trivial (see the example application). After that, you add the outer section (that corresponds to the group header/footer in the traditional scenario), and the inner section to the outer one. The grouped data source should be applied to the outer section, which is of type GroupSection, and the inner section and the elements of the outer section get the correct data sources automatically.

See the Data.doc and the sample application included in the download.

I should confess that I didn't try it with a more than 2 level scenario.

Test Driven Refactoring

As you probably know, the third part of the TDD development cycle is refactoring. After the Green phase, your code works, but it works for the particular set of values that you used in your tests, and it is ugly. The first step is to remove the hardcoded variables so that your code works in a more general situation. This is not actually refactoring, since you change the behavior of the system. This is the second part that everybody likes: moving the functionality around, creating lots of small classes (ravioli code), and injecting dependencies wherever you can. Lots of fun.

The question is, should I write tests for this, or shouldn't I? The tests would mean other 3-step cycles within the first one, other refactoring steps, perhaps becoming a fractal-like structure. What's worse, tests would mean a brittle design that would be hard to change later. No tests would mean problems documenting the class behavior. Recently I chose the latter path, but got lost in the refactoring process, forgetting what I meant in the long run. In addition, being a relative novice and not having a pair (for programming), I'd like to have some guide. The refactoring process remains not very test driven, rather test-constrained, since I don't add any new tests in the process of refactoring. So, refactoring is something driven by my own ideas of a nice design.

Enter Test Driven Refactoring.

The initial idea was to remove the duplicated parts of my tests. Here's an example. Suppose your customer wants the following:
If a user is logged in, she sees the "Edit my profile" and "Logout" buttons.
Next, we ask what is "logged in", and we come with another requirement:
If a user is registered, she can log in entering her username and password at the login screen.
Naturally, we ask what is "registered", and here's another requirement:
After a user has entered her username and password at the registration screen, she can log in using the same username and password.

Let's write the first user story:
1. If a user has entered "test" and "password" into the username and password boxes at the registration screen, then the same words at the login screen, she sees the "Edit my profile" button.
2. If a user has entered "test" and "password" into the username and password boxes at the registration screen, then the same words at the login screen, she sees the "Logout" button.
Each test would probably involve a complicated setup just to check a simple boolean value in the end. Later, we'll probably add some other tests involving various pieces of functionality available to the logged in members. On the other hand, there might be other ways to become logged in. For each, we have to write still another two tests verifying that the two buttons are visible, and perhaps other functionality is available.

We quickly notice that our tests multiply exponentially, much quicker than the features are being added. In addition, we notice that the setup portion of our tests is too big, which is a well known code smell. So, how do we deal with it using the Test Driven Refactoring approach?

Suppose we are past the Green phase, so all the required functionality is there. The Refactoring phase is now divided into three steps. The first is to get rid of the hardcoded constants, "test" and "password". Now we can use any username and password, not just these. The second part is the most interesting one. We notice that all we need for the buttons to be visible or not is a boolean value. Now we see what "Excessive setup" means: instead of using a boolean value for the input, we have provided much more information that will be simply thrown away.

So, we decide that there should be two components A and B, and the A's responsibility is to provide a boolean value of some form to B, whereas the B's responsibility is to show or hide the buttons. The boolean value can take any form: an interface with a single bool property, a variable, whatever. The point is, we can test A and B separately: first we verify that A provides the correct value, and we verify that B uses it correctly.

Recalling the first user requirement, we notice that the functionality of B (and the corresponding test) bears some resemblance. Could we infer the boolean variable from the very beginning? Probably yes, but there are several disadvantages. First, we wouldn't write the initial test, so we couldn't be sure that A and B are integrated correctly. Second, it would be upfront design, which is a sin. And last, sometimes user requirements are much more vague, and it's hard to map them to classes and structures. Recently I wrote a simple search engine, and one of the requirements was that the content should be indexed for faster searches. This requirement would be hard to implement straightforwardly, and the typical TDD process with some obvious refactoring lead me to a wrong direction. After correctly applying TDR, I came up with an intermediate structure (the one that A passes to B) that was identical to the traditional representation of indexed content in a database.

After the TDR part, you are free to return to the "chaotic" or "free-flow" refactoring to achieve even better design. But this part should be one without writing new tests.

Why is it better than the free-flow approach? It turns out that the TDR process gives us a set of components and functionalities that are very well correlated to the client requirements. Thus, there are good chances that the tests won't be broken if you decide to improve your design. These tests are not quite unit tests, since you probably want to split the components into smaller objects. But these tests reflect the client's idea about the functionality, not your idea about the good design.

Tuesday, 6 November 2007

FreshReports is now Inka

It's not on the site yet, but yes, I decided to change the name to something more OS-ish.

For a while I thought about something trivially Arabic, like Mustafah. But I wanted something related to printing, so here it is -- Inka. Sounds romantic, too.

Sunday, 14 October 2007

FreshReports 0.6 is out

PUff, finally I got this paging thing working.. more or less. I have put so much effort into it, I decided to make it a new release.

In fact, I made paging work from the third attempt. First time I took the path of Need-Driven Development, as I understood it. Namely, instead of writing a functional test, I worked step by step and mocked the stuff I planned to add later. The result was a disaster -- I quickly lost all understanding of what works and what is left to be implemented yet. So, at some point I decided to hit the "delete" button.

Second time I did it better. I already had a Page class that held all the element positions in a hashtable. I was pretty sure that once an element appears in this class at a correct position, it should be printed correctly. However, I was treating "unbreakable" sections (ones that cannot be split across pages) as single elements (thus having a single entry in this hashtable). Once I had all the possible tests i could think of pass, I was pretty sure that I got it.

Well, I launched my test application and promptly discovered that everything is printed at wrong positions even if it fits on a single page!

Had to start again.

This time I decided to keep that hashtable, but now I keep all the individual elements' positions there, not sections.

This change broke about half of my tests. I suspected that my tests are a mess, but not that much. Turned out that most of them are not "unit" enough, nor integration. I remember that I should refactor my code, but I'm forgetting about refactoring my tests.

Anyway, I think I've nailed it this time. The code is very ugly at the moment, so I'm not releasing it. I'll be refactoring it as well as add some additional checks about stuff like page margins and such. Probably the next release will see the section margins as well, to get finished with the layout features. But the most important things now are grouping support and aggregates.

Monday, 1 October 2007

TDDing a new feature into the existing code

Suppose you have managed to find out the conditions that lead to a crash. How do you fix it in a TDD fashion? Or, how do you add a new feature to the existing code?

I usually try to resist using the existing code at first. Instead, I modify my production code so that the new conditions take a new path of execution. For example, I assign a certain ID to some object that is part of my test setup, then in the production code I check for this ID, and if it fits, I take the new path. This way I make sure that all my previous tests go to the old path, and since I don't touch the old path code, they will pass for sure.

Next, I force the new test pass as usual. I don't even need to check the other tests -- they are not affected.

Now comes the interesting part. I'm refactoring the new path as usual, watching the new test, but I'm trying it the way it looks "similar" to the old path. I might factor out a new method that looks like the one that's been used by the old path. Sometimes I could even use an old method. If the new test breaks, the old method needs to be modified. Or, I could modify the old method (now I should also watch the old tests). If it's too complicated to incorporate the new behavior, I repeat the same trick: split the path into two, and try to make it one in smaller steps.

With each small step, the difference between the two paths diminishes, so at the end we have a common path of execution, and we can remove our initial split.

Sunday, 30 September 2007

TDDing Web applications: requirments vs implementation details

Now that my Asp.Net testing framework release is getting closer, it's time to think how we could incorporate it into our TDD precess. Specifically, I'm interested in the Red-Green-Refactor pattern.

Suppose I'm trying to develop a site map with a tree-like structure. How do I test the output? In the world of domain logic, or even WinForms UI, the result is more or less well-defined by user requirements: we have to display a table of search results, for example. There's still "more or less", however: we could use a DataGridView, or a third-party grid, or use the form's OnPaint event and draw the results manually. This is what Presenters are for: the actual output is the implementation details, the Presenter is what we test for the search results. In most cases, binding the data to the UI is so trivial that we don't have to test it.

With the HTML output, it's different. Retrieving the data is one thing, but my current task is to display it. So, I reformulate my story: my control has to display a hierarchic data "properly". Here "properly" means proper indentation for items that are deeper in the tree. Purely visual concept, absolutely untestable.

So, I come with several choices. Usually I think of the Asp.Net controls as a high-level structure, and the raw HTML output as the implementation details. So, in other situations, I'd prefer to test the high-level structure. For example, I don't care much if my DataList renders as a table or a set of spans, but I want to make sure that the first Item's DataItem is what I expect it to be. The DataList is a part of a user story, and the HTML output is private implementation details.

With the Web UI development, it's different. Looks like any decision we make is upfront design. Anyway, there are two choices, basically. I can expect some nested DataLists, or Repeaters, or a TreeView, but now this becomes the implementation. Or I can expect some HTML. And the more I think about it, the more I prefer HTML. Now, HTML remains implementation if you think in visual terms. Should I make a bullet list, a set of DIVs, or a table? After all, even a "b" tag will behave like a list item if you apply an appropriate CSS style. But many tags carry a semantical meaning, and if we look this way, the answer is obvious: since we have a list of items, let it be a list tag!

There's also a "purist" approach: you define your own tag, TDD your HTML structure, and apply CSS wisely to satisfy your customer. But the point is, you choose the raw output for testing.

Now that we know what to test, we write a test, and the Red phase is finished. At the Green phase, we just override the Render method and write what we need to make the test pass. At the Refactor phase, we could notice that we use a foreach loop and refactor it into a Repeater, or we could use a server HTML control and build it programmatically, etc. Each way, the refactoring would work only if we haven't hardcoded the entire HTML string into our test. We started with a semantic meaning of the list, let's keep it this way. For example, we can store the output in an XML document, and ignore the node attributes and extra tags like spans and such. Also note that all these server controls appear not as a part of upfront design, but at the refactoring phase, which is what we really want for a TDD process.

Looking at the whole picture, we discover something we didn't expect: our implementation details became a part of a user story, and vise versa. To tell you the truth, I didn't expect the proven TDD principles working in a new field (who said they should?), but they did!

Monday, 24 September 2007

Encoding disaster in Asp.Net

Yesterday I created a few pages that contain Russian text and uploaded it to my hosting provider which is located in The States.

The Russian letters turned into Kryakozyabras (weird text with umlauts). Such things happen when you try to read Russian letters with ASCII encoding (or just cut off the 8th bit).

Further study revealed the following facts:
The problem is only with the static text; dynamically added text appears fine.
The problem is with User controls and regular pages; master pages work fine.
The problem happens with all foreign hosting servers.

What's been really weird is:
Viewing the file in a built-in viewer of my ftp client showed that the file is fine.
Response encoding as well as charset was UTF-8.
The hex editor showed me that the umlauts were actually 2-byte, but different from Russian 2-byte letters.

And the answer is..
.. Visual Studio was saving my files in the default system encoding, that is, Windows-1251. While it was fine for the runtime on my PC, it certainly wasn't for the remote server. So, with all that talking about internationalization, Visual Studio doesn't make its own files encoded properly by default. What's even worse, I couldn't even find a global setting to change that -- I had to resave each file manually.

Saturday, 22 September 2007

Tafiti

A few weeks ago I discovered the amazing new search engine by Microsoft. It uses Silverlight of course, and it is sort of beautiful (they improved over their initial design that looked quite childish). The main fun begins when you choose the Tree view. You actually see a tree with search results hanging like fruits. The tree spins slowly, so that you can wait till the link you want moves closer and then pick it. If you are overwhelmed by the quantity of the results, you can move the slider at the bottom, and the less relevant results will disappear.

Visit http://www.tafiti.com/ and see yourself.

Thursday, 20 September 2007

ItemCreated Strikes Back

Being an old member of the DragNDrop fan club, I'm happily using things like ObjectDataSource in my Asp.Net pages. So, just yesterday I was fighting with the same problem for the, like, 10th time, so I decided to blog about it and maybe next time I'll be wiser.

The ObjectDataSource works great after you've tuned it for your needs. It was a long story about how I have married it with Neo (my ORM tool of choice), but now that all the plumbing code is autogenerated, I can create a simple administrative page in several seconds, while still keeping my UI, model, and data access separate. (Yes I know that you can do it even faster with Rails) The problem arises when you try to do some data processing that doesn't fit well into your model, since it is more view-related.

Let me explain. I'm trying to make a page that would allow to edit the schedule for a fitness club. The page has, naturally, a table: columns are days of the week, rows are hours, each cell has the trainer name and the course title. I've got two ObjectDataSources -- one for the hours and one for the days of the week. And I have a repeater inside a repeater.

Now, you see that there is no way of doing this via just declarative databinding. Even if there are no records about a particular hour/day combination, there should be a table cell. So, I tried to grab the data using the Repeater's ItemDataBound event. The Item here is of type RepeaterItem, and it has a DataItem property that gives me the day of the week. Next, we have to travel up the control hierarchy and retrieve the parent repeater's item, to get the corresponding Hour object. Now we are ready to retrieve the data for the corresponding cell. Next, we have to manually find the corresponding controls inside the cell and fill the data.

Doesn't sound like it's the year of 2007, eh? It actually reminds me of funny tricks I used to do with classic ASP.

The real fun, however, begins when you try to update the values. The truth is, you can't use the ItemDataBound event since it isn't fired again after you clicked the Update button. This makes sense, since the data has been fetched already, so there's no need to fetch it again. The ItemCreated event is fired, however. But the DataItem property is null (as it was the first time before the postback). So, thinking again, you don't have access to your data items at all: they are not persisted, what you have is just property values saved in the ViewState. Thus, no chance to retrieve the data in order to update the correct record with the new values.

There are several workarounds here: you can refetch the data and keep it in a private variable, you can persist HourID in the ViewState and retrieve it on postback, you can even use hidden fields, but all of these are equally ugly. The point is, the DragNDrop thing just doesn't belong here, let's not force it to work. Back in the Asp.Net 1.1, I'd pick a data source manually and have complete control over it. This is exactly what I'm going to do now.

So, the (trivial) lesson is: mainstream solutions work only in mainstream situations. If you have a straight table, go the ObjectDataSource way. If the table is complicated and the data doesn't quite fit, go the manual data source way. If the table is weird -- displays running totals every 10th row, for example, it might be even OK to remember the foreach loop with tr's and td's. Let's just hope it won't get too weird.

Sadly, if I were using TDD for ASP.Net, I won't get into that trap.

Saturday, 15 September 2007

VB Express Limited

As I said in one of my previous posts, I decided to develop FreshReports using VB Orcas. Funny thing, I don't feel I miss any of Visual Studio's functionality, but I miss the add-ins a lot. I can live without TestDriven.Net, but I've got to use Refactor! a lot (they still don't have native refactoring tools in VB). But another thing I miss sometimes is the "attach to process" button. Together with the missing "Debug test" feature of TestDriven it makes it almost impossible to debug your tests. Almost, because you still can use the self-testing feature of MbUnit.

Anyway, at some point I discovered that I'm writing too much Console.WriteLine's and still can't get my test pass. Now, I keep saying it on every corner that I hate all limitations, but honestly, sometimes limiting possibilities can do good for dumbheads like me. So, the reason I tried to debug what's been happening in my code was a smell that something's wrong, but if I could debug it, I just wouldn't pay much attention (old habits). The amount of console output was like some annoying noise that finally woke me up.

I woke up and I told myself, why am I torturing myself? I know a better way of doing this, so let's do it!

Still, I miss the add-ins..

Tuesday, 4 September 2007

Neo is alive!

Finally Neo, my one and only ORM tool I've been using for several years, is resurrected! The project, originally hosted by Codehaus here, has been abandoned for some time, and even the Generics update by Paul Gielens hasn't made it into the main branch.

What makes it different from other ORM tools?

1. Built-in code generation with templated classes.
2. The model classes themselves are not POCOs but contain a lot of DAL functionality (some consider this bad).
3. Possibility to keep all objects in-memory. Very useful for testability.
4. Built-in sql-like query syntax, for both database and in-memory queries.
5. All changes can be saved in one line.
6. Automatic inverse relationships. Spielberg.DirectedMovies.Add(AI) is the same as AI.Director = Spielberg.
7. Child contexts. Say, you have a parent Context that can save data to a database, you can have a child context that can save data to its parent. Very useful in some WinForms scenarios.
8. Probably a lot more.

Some problems include performance issues and a few bugs. But now that the project is resurrected, we can hope that it becomes even better.

The project can be found here, but there are no downloadables yet, just the svn repository link.

Saturday, 1 September 2007

Interaction vs stateful tests, or Falling for Need-Driven Development

A few days ago I started adding paging functionality to FreshReports, and immediately fell into a trap some people call Need-Driven Development (see also this paper). Actually it's not a trap but rather one of thу possible strategies in TDD. However, I felt trapped for some time until just now -- I decided to rewrite my paging functionality using a more stateful approach.

So, how do you do it with NDD? First, you formulate the story, as always. Mine is, "Suppose we have two sections in our report, then if the second doesn't fit on a page, it goes to the next page". Next, I start to code the Page' s CalculateLayout method, something like this:

For Each section In sections

...

If section.Fits() Then

'do something about it


So, we want to code the CalculateLayout method and not get distracted by the Fits method, which is probably a lot to code, so we just mock it out and get a green on CalculateLayout. Next we switch to the Fits method which probably depends on something else, so we mock this something and proceed with the Fits method until it's perfect.

This technique seems fine from a traditional development's point of view. In fact, it is more or less design-first approach. But when I tried to move this way, after programming the TDD way for some time, I was feeling very uneasy. In the TDD fashion, I should have made a simple test that covers everything (section setup and printing), and mocked just the call I am sure of (to the actual element printing method) (note that I could have mocked the call to the section's Print method instead and save time on adding elements to the sections, but only if I'm sure that it works fine with paging). With NDD, I had to write tests for several steps, and since I don't see the whole picture from the start, I don't even know how soon I get to the actual printing. With TDD, I would have let my tests do the design for me, and even while writing the first test I would have discovered that I need a separate Pager class. With NDD, I sort of know the design of the current step before I start writing the test, and that's wrong, because, for example, later I discover that my Fits method needs two additional arguments, and changing its signature will break my tests.

Why have I fallen for it? Partly because I just read an article in which some obviously smart guys told me it's good. Partly because it's tempting. In my case, while writing the first test, I didn't know how to setup this "doesn't fit" idea, so I just mocked it. It was quite easy to write a test, even easier to write the production code, but after that I didn't feel I achieved something, quite the opposite, I felt that I've just made things more complicated. So you see, it's all about feeling good or bad, so it's quite personal.

So, is it that bad? Of course, not. NDD is great for more structured guys. I was feeling helpless because I didn't have a clear picture of what's happening, but that's just me. I prefer to do something quick in a very chaotic way, and then refactor it to make it more structured. NDD is for those who prefer to move step by step.

In fact, I'm using NDD when I encounter an external dependency, such as FTP or file system. I resist a temptation to just save a file, instead I code an interface and use it. I still have to remember to implement it later, but at least it's an end point rather than part of a long chain of objects. So, to avoid this temptation, I made a rule for myself: never mock an interface you haven't implemented yet, save for such thin implementations of external dependencies.

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.