Thursday, 2 June 2011
Look who's got a new home!
Enjoy!
Monday, 5 July 2010
Testing Asp.Net pages with Telerik's JustMock
Guess what, this is what I'm doing right now commenting on the Mehfuz's post. But the main thing I realized reading his post is that this is the perfect example of how using mocks in certain situations can turn testing into a nightmare. The following is not a problem with JustMock, it's a problem with trying to write a unit test involving a complex framework, and isolating parts of it not meant to be isolated.
(Disclaimer: I do understand that the purpose of the original post is not to teach us how to test Asp.Net pages, but to demonstrate the capabilities of JustMock. So, my intent is not to prove that the author is wrong, but rather to take his example as a perfect situation where mock should absolutely not be used.)
So, in order to write the test, we have to
- Mock the HttpBrowserCapabilities class and stub a couple of its properties so that it returns something when needed.
- Mock the HttpRequest class (of course) and make the mock return our mocked Browser.
- Mock the HttpResponse class as well.
- Mock the HttpContext class and stub its Request and Response properties (make the getters return our mock instances).
- Finally, we are stubbing the Page.RenderControl method, and it's unclear whether we do it to avoid exceptions, or just for fun.
Why do we have to mock all these classes? Why do we have to fire up Reflector and dig into the Framework source in order to make our test pass? Because we have this idea that unit testing means testing a particular class in isolation. Somehow all calculator examples left us with an idea that "unit" == "class".
Now, let's back off a bit and consider this: we are testing a high-level ProcessRequest method, which does a lot of lower-level calls to various classes, which are tightly coupled with each other. So, I think it's logical to say that our "unit" is a good part of the System.Web assembly. With that assumption, everything becomes simple: we don't test just our Page instance, we test the whole unit. Assuming we are the developers of the framework, we can also test the lower level methods which have less dependencies, so that we can mock them more easily.
Back to our integration test, here's what it looks like when we use Ivonna. I have omitted all asserts for clarity; instead, we just write messages to the console, as we would in an exploratory test:
[Test]
public void TestingPageEvents()
{
var session = new TestSession();
var request = new WebRequest("Default.aspx");
request.EventHandlers.Page_Init =
(sender, e) => Console.WriteLine("Init fired");
request.EventHandlers.Page_Load =
(sender, e) => Console.WriteLine("Load fired");
session.ProcessRequest(request);
}
This code executes a test against a "real" Web page, with a "real" HttpContext and other necessary objects, so it gives us much more valuable information about the behavior of our system in "real world" situations.Check out a fresh version of Ivonna here.
Monday, 14 June 2010
On structuring your tests
The ideas presented here are nothing new; however, a recent discussion with Dror Helper made me want to state my views on this subject (and make the whole world agree with me, whatever it takes), because to be honest, despite my best efforts in meditation, when I see a class called "MyClassTester" it makes me..
The idea is, if you do TDD, you don't start with a class, because if you do, you already have some design before you have written any tests. So, you start with a user story. Ant let it be a Web app, to be more concrete. Here it goes:
When a user fills the registration form correctly and hits the "Register" button, several things happen:Now, if I were to start writing unit tests for a particular class, which class would it be? The specs say nothing about classes or such. So, first, I decide that it's going to be an MVC app, like all the cool guys doing these days. And I'm going to start with the most exciting thing: my controller. So, I'm creating a class called AccountControllerTester or something. Next, I have to write a test, so I meditate over the requirements, and here's what I think:
- she becomes, in some sense, "registered" in the system;
- an email is sent, containing the confirmation link;
- she's redirected to a particular screen.
- "Registered" is kinda vague, but let's do it with the built-in Membership system. I'll inject this service into my controller, mock the service in my test and verify the call to it.
- Email is easy. A service again, I'll write it later (after the lunch), let's use an interface for the moment.
- Redirection is just return View(".."). Easy to test.
You see, one big problem is that each test class becomes huge. But what's more important, it is hard to tell what your system does. One purpose of tests is documentation, and it should be readable for outsiders. If I am to figure out the behavior of the system in the registration process, where should I look? How do I know that part of it is in the AccountControllerTests, and another part is in the EmailServiceTests?
And still another problem is that you just wrote a lot of code, but made zero business value with it. I mean, I can't register at your site yet! And won't be able until you write all the pieces and connect them together (for which you probably should write an integration test).
To summarize, what you get with this approach is:
- premature, rather than test-driven, design;
- potentially brittle tests (since they are coupled to your classes, you can't refactor easily);
- huge test classes;
- documenting your classes rather than your system;
- no clear relationship between the specs and your tests;
- no business value until you have all the pieces.
There's a better way
Now, let's do it another way. Let's create a folder called Membership, and inside it a folder called "Registration". We're testing the case when we submit valid registration data, so let's make a test class called "IfSubmittedValidRegistrationData". The test methods will be called "ShouldSendConfirmationEmail" etc, so the test output will show something like,WhenSubmittedValidRegistrationData.ShouldSendConfirmationEmail -- passed.This is quite close to documenting your system!
Now, you can still write it as a unit test for your controller, if you prefer, but I suggest you start with integration tests. I use Ivonna for testing, and it makes it a lot easier: my "integration" is only server-side. In addition, I can use several built-in CThru aspects, like EmailSpy, and I can use a lightweight in-memory database. I initialize the posted values (Arrange) and execute the request (Act) in the FixtureSetup method, and all my test methods are one or two lines of code where I verify the results.
- UserShouldBeRegistered -- I just check it via the MembershipAPI.
- ShouldSendConfirmationEmail-- I use EmailSpy that prevents the message from being sent, and saves it for further investigation, so that I can verify that it contains the confirmation link, is being sent to the correct address etc.
- ShouldRedirectToTheWelcomeScreen -- check the Ivonna.Framework.WebResponse.RedirectLocation property.
It's at the refactoring phase that unit tests can provide a big value. Yes we all know that unit testing can lead us to a much better design. But sometimes it is enough to do it mentally. For example, "how would I unit test my controller"? Oh yes, I should refactor the email-related code into a separate class, and do dependency injection. Probably extract an interface like IMessagingService and implement it as EmailService. Whatever. But I actually write a unit test only if I can think of a good name for it. EmailServiceTester totally won't do. TheConfirmationMessageShouldBeActuallySentByEmail is more like it (and the corresponding unit test for the controller is ShouldSendTheConfirmationMessage -- note that it doesn't mention "email"). But in this particular case, it's probably not worth it.
There is another situation when we have a particular feature that produces some output depending on various inputs, and it's not a yes/no situation, like in the previous case. Take searching, for example. You start with an integration test, like before. And make it work. For one of several search form parameters, you know that the search produces the correct results that appear in a grid on the search results page. It would be wasteful to write integration test for every search parameter. So, assume we already have it refactored into several units (note that I don't say "classes"): SearchParamsReader (this is actually the MVC Binder), TheThingThatGivesUsSearchResultsDependingOnTheSearchParams, and SearchResultsWriter (the one responsible for displaying the results). You make three subfolders in your Searching folder (which already contains the integration test), each responsible for the corresponding piece of functionality. Actually, it's probably worth it to make just one subfolder and test TheThingThat.. Again, you don't put everything for testing TheThing.. into one huge class, but you create several classes: SearchByKeyword, SearchByMinMaxPrice etc. This is unit, not integration, testing, and yet it corresponds to user requirements and documents the system behavior. I could refactor TheThing.. into several classes, I could rename it, and the tests won't break.
Here's the recipe for happiness
- Make a folder corresponding to a feature, then a subfolder for a sub-feature etc, until you have a concrete action, like registration or search, or maybe a concrete context.
- Inside, create a fixture for each combination of context + action (like "submitting a duplicate username") and name it accordingly (WhenSubmittedExistingUsername).
- Put all preparation into the FixtureSetup method. You want it to be readable, so refactor all the nasty details into private methods and move them to the end.
- Each check should go to a separate Test method. Name them so that they match the requirements.
- More granular tests, if you need them, should go to subfolders.
- If you can't think of a decent test name (something that doesn't use the class/method names), it's probably not worth writing (but might be useful for driving your design).
Tuesday, 26 February 2008
Saturday, 12 January 2008
Readonly properties and testability
Recently I discovered that the most flexible solution would be to create a special object that just transfers the data between the steps. You don't have to inject anything, if you want some custom data for the second step, you just create your data object manually. Without the dependency injection and inheritance requirements, the steps become completely isolated. You need some sort of controller to drive the flow, and your users can easily implement another controller with any of the steps replaced with different objects and different behaviour.
However, sometimes you, like me, are attached to the old fashioned idea of keeping behaviour with data. You need your class to expose the property and calculate its value:
Public Overridable ReadOnly Property SomeProperty() As SomeClass
Get
Dim result As New SomeClass
'Set some properties
Return result
End Get
End Property
Private _someProperty As SomeClass
Public Property SomeProperty() As SomeClass
Get
If _someProperty Is Nothing Then _someProperty = CalculateValue()
Return _someProperty
End Get
Set(ByVal value As SomeClass)
_someProperty = value
End Set
End Property
Protected Overridable Function CalculateValue() As SomeClass
Dim result As New SomeClass
' Set some properties
Return result
End Function
A similar pattern can be applied to value objects. The trick is to make the associated private variable nullable:
Private _someProperty As Nullable(Of Boolean)
Public Overridable Property SomeProperty() As Boolean
Get
If Not _someProperty.HasValue Then _someProperty = CalculateValue()
Return _someProperty
End Get
Set(ByVal value As Boolean)
_someProperty = value
End Set
End Property
Protected Overridable Function CalculateValue() As Boolean
'Do stuff
End Function
Finally, let's try a similar thing with enumerables. Typically, we expose an enumerable as a readonly property, and fill the values at the initialization stage. Here we do a similar trick, but on a certain condition. We add a boolean property AutoCalculateValues and calculate them only if it is set to true, which is the default behaviour:
Private _autoCalculateValues As Boolean = True
Public Property AutoCalculateValues() As Boolean
Get
Return _autoCalculateValues
End Get
Set(ByVal value As Boolean)
_autoCalculateValues = value
End Set
End Property
Private _someProperty As IList(Of SomeClass)
Public Overridable ReadOnly Property SomeProperty() As IEnumerable(Of SomeClass)
Get
If _someProperty Is Nothing Then
_someProperty = New List(Of SomeClass)
End If
Return _someProperty
End Get
End Property
Protected Overridable Sub CalculateValues(ByVal list As IList(Of SomeClass))
list.Add(New SomeClass)
'...
End Sub
This time, the property is not settable, but the idea that it is initialized by default but the initialization can be switched off.
So, what are the advantages? In terms of testability, we can set the desired values directly, instead of using mocks, which simplifies our life a bit, and our tests become even more clear. But the main point is about reuse. Testability with mocks implies that one can modify the behaviour of our class by inheritance. A user of our framework can create a descendant of our class, overriding the property, and inject it into the workflow, just as we do in our tests. Making the property settable, on the other hand, makes it possible to extend the behaviour by composition: a user can, for example, add another class that sets the property in response to some external conditions. Another, more important, possibility, is to set the property manually. For example, on a Web page, the block elements are usually go under each other, but sometimes you want to position your div manually. You don't override the div class, you just tell it, "don't calculate your position, I'll do it myself". Note that the old inheritance possibility is still there -- you can override the CalculateValue() method if you want.
So, the system definitely becomes more open. This will definitely make the users of your component happier, but also opens more possibilities for misuse. For example, I could set the value that would put the system into an invalid state. However, the same result can be "achieved" by inheritance, only with more efforts. So, apart from validation, the best solution is writing docs properly. And remember that what seems like misusing to you might be a perfect way of using for others.
I'm using these ideas for some time with Inka, and I discovered that my design has improved. Each time I'm tempted to mock a parameterless method, I'm trying to convert it into a property, and then make it settable. I discovered that I have less dependencies and better decoupling, less pulls and more pushes, less methods that cover all possible situations, more small classes specifically designed for each situation.
Inka Layout, take three
In short, first I tried Need Driven development: implement it step by step, mocking out the next step before implementing the current. This became a disaster: too much upfront design for me. Without seeing the whole picture, I was never sure that it works, much less that it works the way it should.
My second attempt was much better. At least it began better. I implemented a quick and dirty solution first, then added a few more integration tests and made my solution a bit more complex, then began to refactor. The refactoring stage took forever though. I still haven't finished it in the last release, so I was too shy to publish the code. With only integration tests in place, I wasn't seeing the correct direction of refactoring, so I was doing it blindly, and it took ages to figure out why this particular test broke when I did this simple refactoring.
Now it's the third attempt, and I've already abandoned version 3a. But I don't want to talk about it yet, until I see the results. I should say that the trunk version is the same as used in the last release, since I decided to put the new experimental version in a separate branch.
Saturday, 10 November 2007
Test Driven Refactoring
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.
Sunday, 14 October 2007
FreshReports 0.6 is out
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.
Sunday, 30 September 2007
TDDing Web applications: requirments vs implementation details
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!
Saturday, 15 September 2007
VB Express Limited
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..
Saturday, 1 September 2007
Interaction vs stateful tests, or Falling for Need-Driven Development
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.
Saturday, 25 August 2007
ASP.Net testability.. finally the way it should be!
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)
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.
Wednesday, 15 August 2007
Adventures in test-driven development Part 4: What's next?
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
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
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
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
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:
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.<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
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
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
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:<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
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
Next time we are going to make a huge refactoring, since it's going to make our test-driven life a lot easier.