Testing framework is not just for writing… tests

Quick question – from the top of your head, without running the code, what is the result of:

var foo = -00.053200000m; 
var result = foo.ToString("##.##");

Or a different one:

var foo = "foo"; 
var bar = "bar"; 
var foobar = "foo" + "bar"; 
var concaternated = new StringBuilder(foo).Append(bar).ToString(); 

var result1 = AreEqual(foobar, concaternated); 
var result2 = Equals(foobar, concaternated);


public static bool AreEqual(object one, object two) 
{ 
    return one == two; 
}

How about this one from NHibernate?

var parent = session.Get<Parent>(1); 

DoSomething(parent.Child.Id); 

var result = NHibernateUtil.IsInitialized(parent.Child);

The point being?

Well, if you can answer all of the above without running the code, we’re hiring. I don’t, and I suspect most people don’t either. That’s fine. Question is – what are you going to do about it? What do you do when some 3rd party library, or part of standard library exhibits unexpected behaviour? How do you go about learning if what you think should happen, is really what does happen?

Scratchpad

I’ve seen people open up Visual Studio, create ConsoleApplication38, write some code using the API in question including plenty of Console.WriteLine along the way (curse whoever decided Client Profile should be the default for Console applications, switch to full .NET profile) compile, run and discard the code. And then repeat the process with ConsoleApplication39 next time.

 

The solution I’m using feels a bit more lightweight, and has worked for me well over the years. It is very simple – I leverage my existing test framework and test runner. I create an empty test fixture called Scratchpad.

scratchpad

scratchpad_fixture

This class gets committed to the VCS repository. That way every member of the team gets their own scratchpad to play with and validate their theories, ideas and assumptions. However, as the name implies, this all is a one-off throwaway code. After all, you don’t really need to test the BCL. One would hope Microsoft already did a good job at that.

If you’re using git, you can easily tell it not to track changes to the file, by running the following command (after you commit the file):

git update-index –assume-unchanged Scratchpad.cs

scratchpad_git

With this simple set up you will have quick place to validate your assumptions (and answer questions about API behaviour) with little friction.

scratchpad_test

So there you have it, a new, useful technique in your toolbelt.

Comments

Pablo Ruiz says:

LinqPad rocks as scrachpad.. 😉

Miguel Madero says:

I like the –assume-unchanged switch. That’s the main reason I didn’t like the scratchpad idea when I saw it in our codebase.

That said, I still think that there’s some value in commiting ‘some’ of those assumptions. For those cases we could move them from ‘scratchpad’ and to a more persisted area. Maybe an assumptions folder. Some people is against testing libraries others than your own, but I see some value on doing that. But I also see value in splitting them from your tests. Assumptions can serve as documentation and  to test for regressions (e.g. NHibernate breaking our previous assumptions on every release). We could even make assumptions about existing bugs on our dependencies and identify when the bug is fixed on a new release.

For quick and transient assumptions I like using Mono’s REPL or the REPL Add-in for VS. I’ll give LinqPad a go.

Anonymous says:

I can answer without compilling

1. -.05

2. false in both cases, baceuse object.Equals and equality operator on objects uses reference equality: first string is interned, while second is not. So they are two different objects.

3. false, in case when Id is actual identifier of Child.

RollerSMB says:

I have to admit to having many pointless console apps 🙂

Having said that, I don’t have THAT many, as a lot of the simple stuff can be tested using the immediate window directly, eg, had to illustrate to someone how the order of logic operators worked, and could just declare the bools and run the expressions directly in immediate window.

(ps, I could answer all of those too!  honest.. :P)