This blog’s main URL has changed: http://blog.johanneslink.net
The new feed URL is http://blog.johanneslink.net/feed/
This blog’s main URL has changed: http://blog.johanneslink.net
The new feed URL is http://blog.johanneslink.net/feed/
7 years ago the agile manifesto was published.
Frank Westphal interviewed Henning Wolf, Jens Coldewey, Jutta Eckstein and myself about how we see, feel and live it today. Since we are all German native speakers, the podcast is in German, too.
Have you ever had a Fit(Nesse) test suite of more than just a few pages? Have you ever tried to consistently change the names of test pages, fixtures, columns, commands or anything that is being used a few dozen or a few hundred times across the whole suite? Have you ever wanted to get rid of the 14 setup tables that were copied from your first test page into all others? Have you ever wished you could reorder columns, arguments or parameters in your fixtures?
You get my point. Doing “refactoring” in large FitNesse test collections is a real pain in the neck. I put “refactoring” into quotes, because – strictly speaking – the kind of changes you want to bring about your test pages don’t support the definition of the word refactoring:
Code refactoring is any change to a computer program’s code that improves its readability or simplifies its structure without changing its results.
Since we are not dealing with code (one could argue that) and since many changes actually do change the test suite’s behaviour, I probably should call it “reorganization”. But refactoring sounds way cooler; at least it did in 1999.
Well, to perform these reorganizations your current best choice is to use some regex-based search and replace mechanism and hope that you get the stars, dots, backslashes and question marks right. And even then you never feel sure that you found everything and kept the somewhat weired wiki syntax in place when pressing the “Replace All” button. I haven’t seen – and could not find – a tool for FitNesse that tries to tackle these problems. So I went boldly ahead and made my own: ReFit
The long term goal of ReFit is to provide test maintainers with a DSL for refitting (puns++) their tests to the testing language they have in mind and to the code base under test. Currently ReFit is nothing more – and nothing less – than an extended Groovy-Console which provides you with a way to navigate through a FitNesse test suite, change objects of the suite and finally commit all changes back to the file system.
How you go about installing ReFit, starting the console and hooking up to a particular suit is described here. To make your mouth water – or your bowels contract in pain – I’ll present a single example script:
suite.pages.findAll { page ->
page.name.normalize() == "setup" &&
page.fixtures.any {
it.name.normalize() == "import"
}
}.each {page ->
page.fixtures[0].remove()
}
This script will find all “SetUp” pages that also have an “Import” fixture and then remove the first fixture of those pages. What you can guess from it is that one can use all of Groovy’s capabilities as a dynamic language to manipulate a straightforward object model of a FitNesse test suite.
This hardly couldn’t be further from a real refactoring DSL. I am awaiting the astute users’ recommendations to move ReFit further into that directions. And please, if you think that’s the wrong path to follow, tell me as well!
My personal opinion on this is “only barely – if at all”. If you can read German then Jens Coldewey’s very good summary of the problems you run into if you try is just for you. Here is my adhoc translation of a section in which he characterizes his experience with refactoring large C++ legacy systems:
To rework and refactor a whole system like this can take years. Languages that enforce such big rework should not be used anymore except in very special circumstances. Would you buy a new car the engine of which was developed in 1980 and which contains many concepts of his 1960 precessor?
Switching regularly between .NET and Java definitely does not facilitate remembering the details of one platform or the other. For me, however, it made me see how similar both platforms are and consider C# to be a (slightly) improved version of Java.
For the most part, I still think that´s true. Explicit properties, delegates and events make coding certain programming idioms somewhat smoother and more readable than using bean conventions and anonymous inner classes. That said, I still shy away from doing serious development with C# since the programming experience and the available tool set is so much worse for C# that it makes me shudder. And yes, I tried many of the 3rd-party add-ons; they can relieve some of the pain but they don’t go half the way towards IDEA IntelliJ or Eclipse. To be frank, I haven’t used MS Visual Studio 2008 yet, but I cannot imagine Microsoft to really change the equation.
Let’s get back to the core topic of this entry. There’s one thing where I consider that the designers of Java made a much wiser choice than the C# folks: In Java any public method which is not declared to be final is virtual and can be overridden in a subclass. In C# the default assumption is the other way round: Unless you declare a method explicitly to be virtual it will be statically bound, i.e. a subclass can declare a new method with the same signature but calling the method on a reference of the superclass will always invoke the superclass’s implementation regardless of the object’s actual class.
This difference bit me when I wanted to extend a tool that exists in both Java and .NET: FitNesse. FitNesse comes with a TestRunner to enable running the tests outside the wiki. The implementation (approx. 200 LOC) is very similar in Java and C# and all I wanted to do was to add two lines to a single method:
public class TestRunner...
public void Run(string[] args)
{
...
fitServer.EstablishConnection(MakeHttpRequest());
...
}
public string MakeHttpRequest()
{
string request = "GET /" + pageName +
"?responder=fitClient";
...
return request + " HTTP/1.1\r\n\r\n";
}
This sounds easy enough, so I created a sublass
public class MyTestRunner : TestRunner...
public string MakeHttpRequest()
{
return base.MakeHttpRequest() + "&myParam=myValue";
}
If you replace “base” by “super” and make the M of “MakeHttpRequest” lower case, this solution works as expected in Java. It does not work in C#, though, because my overridden implementation of “MakeHttpRequest” will never be called. Of course, the compiler warned me about that on first build, but since I did not want to change the original library I ended up with copying all code from TestRunner into MyTestRunner plus copying another 40 lines from TestRunnerFixtureListener into MyTestRunnerFixtureListener.
Thus, the seemingly “more secure” design choice of C#’s founding fathers lead to 250 lines of IMHO completely unnecessary duplication. Two reasons for this decision come to mind:
I trust the statements of JVM experts on the first issue, who claim that in our days of highly optimized Hot-Spot-Just-In-time compilation there is no longer a performance hit. As for the second point, a compiler warning, which encourages me to use the override keyword, is enough security for my taste.
In the end it boils down to a rather fundamental difference in attitude: Should I consider extensibility a basically good thing or do I want to protect developers against their own errors as much as possible? I’m strongly rooted in the first camp because There is no such thing as a foolproof programming language!