Thursday, September 20, 2007

Using NUnit For GUI Prototyping

I love NUnit. I am starting on a new project, so what better way to prototype some primordial ooze, than to bang out some test cases?

It was all groovy until I realized one the elements I must prototype is a custom user interface control.

This did not provide much of an issue; I simply made a new set of test cases that displayed a form with the control in it.

Dude! That's not very automated.

True enough, but we are preempted by getting the job done. These cases are isolated enough that they can be excluded from the non-visual automated test cases.

Let's just call these UI Tests, since they require user-interaction to complete. Perhaps there's no need to label them, but I feel it requires differentiation, because these test cases cannot run "in a vacuum" on your CI server.

So why wouldn't I just start building a prototype application, and do it that way?

Another bonus is that by implementing debug "harnesses" of "typical" event-handler scenarios (e.g. tracking selections, event-handler firing), one can actually debug a lot of behavior, and even use Assert to validate.

This is awesome, because it allows you to really focus in on both the client-side (How do we want this code to look?) and the custom control side (Are events firing in appropriate sequence?) I maintain you can't concentrate on this in the context of all the noise of "bringing up" a prototype.

And for the memory-challenged (me!), you now no longer have a reason to "forget" to test any user interaction scenarios before committing.

For example, the custom control had to present a grid of items in 1 of 8 possible orderings (RowMajor/ColumnMajor,LtR/RtL,TtB/BtT) two-cubed equals 8. What better way to systematically run through all 8 presentations? Want to do that manually? I didn't think so. Granted, the user must manually validate the orderings (for now), but the important part is the completeness.

For example, I was implementing ISelectionService on my custom control, so I created a debug harness to manipulate the selection in all the different ways supported in the control's implementation (there were 6).

Just to show I'm not totally heartless, here is some sample debug harness code:

ISelectionService iss = sender as ISelectionService;
   Assert.IsNotNull(iss, "sender as ISelectionService failed");
   bool wasselected = iss.GetComponentSelected(cea.Cell);
   int oldcount = iss.SelectionCount;
   _list[0] = cea.Cell;
   iss.SetSelectedComponents(_list, _st);
   switch (_st) {
    case SelectionTypes.Add:
     Assert.IsTrue(iss.GetComponentSelected(cea.Cell), "iss.GetComponentSelected() failed");
     Assert.AreEqual(oldcount + (wasselected ? 0 : 1), iss.SelectionCount, "iss.SelectionCount failed");
     break;
    case SelectionTypes.Primary:
     Assert.IsTrue(iss.GetComponentSelected(cea.Cell), "iss.GetComponentSelected() failed");
     Assert.AreEqual(1, iss.SelectionCount, "iss.SelectionCount failed");
     break;
    case SelectionTypes.Toggle:
     Assert.AreNotEqual(wasselected, iss.GetComponentSelected(cea.Cell), "Toggle failed");
     Assert.AreEqual(oldcount + (wasselected ? -1 : 1), iss.SelectionCount, "iss.SelectionCount failed");
     break;
   }

Pretty much what you would verify visually, but let's not forego automated checks to keep everyone honest.

There were additional debug harnesses for validating Enter/Leave/Click event firing, etc.

I'm sorry, but that's just plain hard to get done if you are "embedding" this into a prototype "product". This way, the test cases make you operate the UI in the specific way that the debug harnesses are Asserting for.

Now granted, the user must cooperate with the test case's objective, and the Assert strategy of a debug harness is only as good as the effort you put into it, and can be tantamount to actual use cases. Don't Fret! This is a great thing! You can now refactor that code and re-integrate it back into new test cases. Well done!

Wednesday, September 19, 2007

My Karma Ran Over My Dogma

C'mon, sing it with me...

Jabba, Jabba, Jabba-jabba jing-jing-jing ($$$)...

Anyway, that's what I'm singing there, don't know about the rest of y'all...

Oh yes, you are blindly singing along with the "correct" words.

It is a cute song. Much cuter than the posse themselves lol.

What?? Was that a swipe at The Posse!?

Well, kind of. Don't get me wrong; their podcasts are informative, and I listen to them religiously; it helps me keep track of the alternate reality that is Java.

As a member of the .NET alternate reality, I am really cheesed-off at their ignorance of .NET related topics. They are so dogmatically entrenched in their canon that they cannot see the ways of others.

It is wise to know the ways of one's enemy...

That is my favorite line in that whole movie, and I use it as a strategy. It sounds evil in Russian, doesn't it?

Yea, well aren't you just a hypocrite too? What kind of Java did you ever use?

Well, a bunch more than you might think. I'm quite happy with all of those J acronyms. I've deployed J2EE application servers, I love Eclipse and not NetBeans, JSF is just ASP.NET (but thank God they have a component model now), etc.

I've used it enough to tell you that not having syntactic support for properties sucks the big banana. JavaBeans is just a necessary dogma in order for people to actually build tools and interoperable components. Oh, you didn't want to use Notepad and a Command Prompt as your IDE? I think it's a big reason GUI development in Java sucks so bad. If it didn't suck, you would see way bigger penetration. It's too bad I think; we got stuck with VB6 instead (well not me personally; I was using Delphi and laughing hard the whole time). Not having syntactic support for event listener invocation is also a non-brilliant idea.

The deal is, it's classic Yin-Yang. We won't debate which is which here, perhaps in a poll. These two alternate realities feed off one another, but most of the people on both sides are so dogmatic, they don't see it. The agnostics and atheists see it though, because they are opportunistic. That's why Java has annotations, finally. I've been using annotations, closures, and reified generics for years now, sorry you took so long. In fact, I'm still using better features that you don't have, like real properties. Argue all you want on that one, I'm with dogma there.

And as a final rememberance on the whole managed code thing, who remembers the UCSD P-System (besides me and Jim)? JVM/CLR my ass, that was an adventure (yes I wrote code in it, no pity necessary), and I'm not even sure that was the first one.

You tell'em, bruvva....

Just remember, it's all opinion, just like what you're reading now, and my opinion is that Their Employers are just-as-big or bigger than the one they constantly demonize, and they can believe what they want about how pure policies are (oh My Company is a perfect saint, ask anyone that works there), but we all know large corporations (composed of greedy humans) are greed-based; if it wasn't greed-based, it wouldn't be operating in their shareholder's best interests. How fast would you be bailing on your XYZ Corp shares if you heard at the shareholder's meeting:

We will no longer be seeking to increase share price or dividends or market share.

That is the most absurd idea ever, we all know it.

Well, isn't Greed an extreme word?

Not if you've been paying attention to headlines over the last decade. Remember Enron? No greed there, huh?

Perhaps it's just that you are bitter they are popular and you are not?

If I were popular, I probably wouldn't have the balls to rip on them.

Tuesday, September 18, 2007

What Happens in Vegas, Stays Off Corporate Servers!

This post contains descriptions of nudity and adult language. Reader discretion is advised.

I tell you, it pays to share an office with members of IT Operations, and this is why....

I was busily typing away at some NUnit test cases, when my office-mate exclaimed (she was trying to free up some space on a corporate file server), "Oh my God!"

My mind immediately sank to the gutter. "You found porn!?" I asked in anticipation.

She confirmed my wild hypothesis. "Let's see...." Mind you, this was not found on someone's laptop, but on a corporate file server. I was quite taken aback, since I figured in this day-and-age, no one would be that careless.

Surely enough, there were some images of two younger women, completely nude, having strap-on sex in a hotel room. By the way, they were both shaved, and having a good time with it.

The game was afoot. Just who did these pictures belong to? Fortunately, there was more evidence. My office-mate was busily emailing her IT Operations counterpart with the full UNC (pun intended?) path to our source of amusement.

Most of the pictures were of the same (hot) girl posing with various other "working" girls. Unfortunately, no one was recognized as an employee. Then, we finally got to one! It was one of our salesmen; he should have stayed behind the camera lens.

But why store these on our server? Was he afraid his wife would find them?

It was a good theory, until we found out that it was his wife in the pictures!

Tuesday, September 11, 2007

TDD Is For Me

I just read this blog entry, from one of my favorite authors:

TDD- It's Not About Testing... Except When It Is

That pretty much sums it up.

What kind of self-referential crap is that? Check your pipe for residue....

No, really. Here is the anecdote.

I was heavily refactoring some "serial port" code, and I was paying close attention to the section of code responsible for filling the input buffer and watching for the "line terminator" character, which signals a complete "message".

I immediately got concerned about off-by-one and buffer-overrun situations, e.g. what if my input buffer was shorter than my longest possible incoming packet? Did things fail properly?

You and your fail correctly crap....

As I say, anyone can code for success; it takes skill to code correctly for failure.

The astute reader knows exactly what happened next, but for the sake of the rest of you, I will continue the story.

First, the buffer length was refactored such that it could be configured. Next, a test case was established that set the buffer size to less than the size of the expected message. Next, run the test and adjust expectations accordingly.

How utterly boring and predictable. Were you able to adjust?

Certainly. Needless to say, fears were confirmed; some minor tweaking was necessary to cover the smaller-than and equal-to cases.

I can sleep easily now.

Disclaimer

Look, this is humor, so put away the flame-thrower! Just have a laugh and go on your merry way....