The Value of a TestApp


The single greatest programming I’ve ever received is this: Use test apps religiously.  In this world of Nunit and the like, perhaps I should explain what I mean by test apps.

What is a test app?

A test app is simply the absolute smallest amount of code that you can use to create your new functionality in.  In my case, I usually create a new Windows Application in Visual Studio and put starter code in the Load event.  If I feel like being extravagant, I’ll drop a button on the form and put the hook code in there instead.  That’s it; the entire framework of a test app.

A test app is meant for creating a single piece of production code.  It lives for the code, it dies for the code and nothing beyond what is needed to support that code should *ever* be added.  Do not fall into the trap of creating a complex test application that can handle dozens of bits of code.  This is unmanageable and defeats its own purpose as the code in it gets further removed from the real code over time.  Disk space is cheap, don’t be afraid to create a few folders.

Test apps are not to be confused with Test Harnesses and utilities like NUnit.  These tools are invaluable but are meant to be applied to the full body of code.  The test app is only for one little bit of functionality.  If you really feel that compelled to use NUnit everywhere, you can wire it into your test app as well 🙂

Why a test app?

  • Lightning fast revisions and compilation. Since the test app is so small, you can test, fix, build and retest several times in the same amount of time that it would take to compile the main application once.
  • Fully Isolated debugging. If it breaks in the test app, you are 99.999% sure that it is your code. In the main app, things can break for an almost infinite number of reasons. Perhaps someone checked in bad code, the database is down, someone playing with test data – all of that is completely unrelated to the code you are working on but slows you down nonetheless
  • You get full debugging abilities on the test app. This may not always be the case in your test environment. In many test environments, you are limited to writing to logs for everything. This is nice, but far less useful than a fully interactive debugger.
  • Rich testing. You can define any number of scenarios to run your new functionality through simply by copy-pasting a line a code in the Shell and changing a parameter or two.
  • Performance testing. If you suspect that your code might be a bit slow, it is trivial to set up loops and timers in the test app. I can run my code through millions of iterations with almost no effort in the test app. Try setting up this type of test in the main application and you will immediately see the perks.
  • Easy experimentation with unproven algorithms. There are times that you need to feel your way to a solution in code. This provides a completely safe environment to do this in. Trying to do this in the main app often requires a lot of instrumentation in order to call the new logic, all of which might just have to be undone if the algorithm doesn’t work.
  • Known code. Because of how small the test app is, odds are good that you will walk through the code in the debugger quite a few times while working on it. This simple task might be all but impossible in a shared dev environment.
  • Generic. In creating your new code so that it can be tested in the harness, you might discover that it works just fine if you define a parameter as IEnumerable instead of ArrayList or a custom collection, making it potentially even more useful to the main application.
  • There’s also a free bonus benefit at the end of the article

The Code

Here is where a little design goes a long way.  Write your new logic so that everything can be passed into it as parameters (your eventual production code will thank you for this!).  If you are creating a new class, provide constructors that allow it to be set up with enough information to make the class think it is in the real app.  Ideally, your new code should know nothing about it’s environment other than what is fed to it.

ABOVE ALL – TREAT THIS CODE LIKE YOU WOULD PRODUCTION CODE.  No hard-coded values, no assumed paths, etc.  If you need something like that, pass it in as a parameter.  This is so that you can literally copy-paste this logic into the larger application unchanged.

The Shell

Create the absolute least amount of code needed in order to support the functionality you are about to write.  By this, I mean hard-coded parameters and the like.   The shell is meant to be dirty, ugly code that you wouldn’t show to anyone – even for money.  Its sole reason for existing is to be a fast way to call your new functionality, not as a show piece for CodeProject.

Connect it up

Go back to your shell code and connect it to your new code.  Does it work?

Test it and test it again

Once you have it working the way you want with the expected inputs, you can play all sorts of games with the code.  Hard code values in the parameters to test out error handling or to simulate conditions that may be very hard to reproduce in the main application.  Testing and fixing these sort of issues in a test app is easily 10 times faster than trying the same thing in the main application.  The bigger the main app, the greater the advantage of using a test app

Drop it in

Since you went through the effort of putting your new code into its own black box of sorts by parameterizing so much of it, dropping it into your real application is almost a no brainer – just feed it the parameters it needs and you are pretty sure that you have a reasonably well tested body of logic in place.

Revisit

Once you have the code in there, run it through it’s paces in the main app.  If it breaks because you have, say, a null coming in where you hadn’t planned for one, its nothing to fix.  Just create another test in your Test App to simulate the new situation and debug away happily.  When fixed, drop the updated code back in again.

I Object!

This is great and all, but isn’t this actually extra coding?  Yes, slightly.  The shell might take you 30 seconds to create if you type really slow, and then the main hooks another 2-3 minutes or so.  The rest of the code you have to write anyway so you might as well do it in a place where you can beat the snot out of it easily and quickly.

No way, my test environment is SO complex.  That might be true, but that doesn’t mean the functionality you are writing needs to know about it.  Odds are good that it can be abstracted pretty easily.  Not always, but more often than you might think.

Enjoy!

I have written several thousand test apps in the 12 or so years that I have been using them and have never thought even one to be a waste of time.

Freebie benefit

Remember I said that you should never show your test app to anyone?  That’s not entirely true.  There is one person who will be *very* grateful for it – the guy who comes to you and asks: “How do I use your object?”  You just toss him your test app and he can immediately see not only how to call it, but what you had in mind for it when you created it.  For most of us, a quick example with actual code is worth a 1024 words.

Speaking of which, here’s a somewhat contrived example of a test app:

Sample Code

Worthless Backups


What is with corporate backups? I’ve been in this field over a decade and have yet to actually see a Restore of anything actually work. Seriously! Files, databases, anything. Anytime that I’ve been in a situation that needed something restored from backup, the backup was either corrupted or the systems people lacked the ability to selectively restore only the item needed.

I actually had a system admin tell me that in order to restore a file, he would have to restore the whole volume. This was all the worse because this was a Fortune 500 company and I know that their backup software and systems were state of the art. They just put a moron in front of it and assumed it would still do miracles.

Companies spend a fortune on backup software, disaster recovery planning and the like, yet, when it is really needed, the data is nowhere to be found – as the recent incident in Alaska is yet another indication. (Alaska Department of Revenue vaporizes $38 billion account)

Microsoft “Tool” Book Covers


This has been bugging me for some time and I have to vent about it. For some years now Microsoft has been putting tools on the covers of its technical books, which is fine and even makes sense. But, shouldn’t they put NEW tools on them, or at least the coolest tools to be found? Instead Microsoft has used old, dirty, rusty, bizarre and/or antiquated tools! Just what message are they trying to convey?

Some examples
http://www.microsoft.com/mspress/books/6715.aspx
http://www.microsoft.com/mspress/books/5200.aspx
http://www.microsoft.com/mspress/books/5621.aspx
http://www.microsoft.com/MSPress/books/9692.aspx
http://www.microsoft.com/MSPress/books/10512.aspx

Looking at the upcoming titles, it does look like they have removed the rusty ones, but some of tools chosen are simply bizarre. A horseshoe for SharePoint? Pliers for Communication? An old drill for driver programming? Are they saying that their software tools are merely old, or old AND obscure? Perhaps they are trying to convey that the information within is outdated?

Don’t get me wrong.  I’m a huge fan of these books as the content is usually top notch.  It’s just that the first questions that come to my mind when I see these covers is about the tool. 1) What the heck is it? And 2) What in the world would a person use that for? Neither of those are questions that are particularly favorable to an entire line of books dedicated to software tools.

My non-tech friends see them and ask: “Why do you have so many books about old tools?”

Approval Workflow is Broken on Publishing Sites


I ran into an odd issue the other day where the Approval workflow for a Publishing site simply would not work. .Net 3.0 was installed properly and the site was otherwise functioning perfectly so it didn’t appear to be a problem with the install.

What was happening was that when I pulled up the first page in a workflow, I received one of these two messages:

“The form has been closed” – which is the lovely generic InfoPath version of the Sharepoint “An error occurred” message. Not terribly useful

– or –

“The server is currently being taken down for maintenance. Check with your system administrator to see when this server is scheduled to come back online.
Click Try Again to attempt to load the form again. If this error persists, contact the support team for the Web site.
Click Close to exit this message.”

… yet, the site was running fine aside from the workflow.

The Solution
Somehow the site had gotten itself into a partially quiesced state where some of the site was convinced that the whole farm was quiesced while other parts thought everything was running fine. The fix was to go into the Quiesce Farm option in

Central Administration > Operations > Quiesce Farm and then restart the farm. After that, everything worked fine.

Quiesce farm

An interesting thing that pointed even more to this was the error in 12/LOGS that read: “Loading event log failed, because the form was quiesced”.