Tuesday, August 31, 2010

Unit Testing Perils

Adding unit tests to existing code is nowadays applauded for being progressive, almost borderline pedestrian, for most software development shops. This was not the case when I began writing automated unit tests several years ago. It now feels otherworldly to see greater acceptance of unit testing primarily because I'd greatly toned down my advocacy for it. This shift in attitude includes a (substantial) decrease practicing test driven development (TDD). Unit testing can not simply be applied on blind faith hoping to cure all of one's software ills.

Not long ago, I and other developers on a .NET software project were retroactively adding unit tests (no TDD) for recently produced C# code. Part of the process involved removing any cruft specifically code that was not being called by any other code. The motivation was to help increase code coverage by removing any untouched lines of code. We relied on the static analysis features of the Visual Studio plugin, ReSharper, to reveal these isolated areas of code. In ReSharper parlance, Find Usages handles the work of hunting down any dependencies for symbols and functions.

One of those areas ReSharper indicated that no usages found were for a few simple getter/setter properties of a class. This code was then confidently removed. However, it was later discovered that the removed code did indeed serve a purpose and was providing functionality to one of the GUI screens of the WinForms application. More specifically a few of the columns in a 'DataGridView' control that allowed editing no longer did so. They unexpectedly became read-only.

The GUI screens had no tests. The discovery was made via manual end-to-end testing. This 'DataGridView' control was bound to the properties of the class. It inferred from the properties whether they were getters, setters, or both. The 'Set' accessor of the properties were naively removed since the code we wrote did not seem to call it. The grid control however was binding to it and passing values to and from the properties. No setter accessors now meant the associated columns had become effectively non-editable.

Realizing our mistake we rolled back our original edits for that class and cautiously reviewed all other recent refactorings.

Joel Spolsky once stated that manual testing is all you need in developing quality software and that unit testing provides no notable value . Others taking the inevitable opposing view immediately went on the offensive denouncing his claims. Joel's view is more an over reaction to all the TDD zealots who, whether intentional or not, seem to be deemphasizing the value of old fashion manual testing. Meanwhile, the dissenting voices are manifesting as a fear that their do-no-wrong methodology (and possibly their identity) might possibly amount to nothing. Both views are too extreme and leaning one way or the other can cost you in other areas. You need to continually find and maintain a balance in testing and not become complacent with whatever approach you take.

Yes, integration-style tests might have helped in exercising and validating the correct behaviour in the UI but even that might give you a false sense of security. Manual testing does have its virtues. Without it, you might overlook the human elements of UI functionality, design, and usability. Just like it is an incorrect assumption that no compiler errors means your application is fully functional and ready for end-users.

Also, these were CRUD operations. In my experience they tend to be the least risky part of an application, least likely to be buggy, and the quickest to identify and fix. The cost of writing and maintaining these sorts of unit tests do not warrant their benefit. Is it really worth your time and effort chasing after an unrealistic 100% code coverage? You learn your lesson then you move on (part of continually defining the proper testing balance). Regardless, you should confirm that your seemingly harmless refactoring does not produce unwanted side effects. Unit tests help with that but not by themselves.

Putting the merits of unit testing aside for a moment, the inability to easily detect how the .NET framework is referencing and interacting with my code can be somewhat irritating. This datagrid binding issue is another one of those features in .NET where it does something behind the scenes on your behalf (automagically!) but it is not clear (at least not from a coding perspective) what and how it is doing it. I'd experienced this before when trying to implement paging using NHibernate in an ASP.NET GridView control and it was frustrating. Wait until the havoc WebMatrix, LightSwitch, and friends will unleash on the .NET community.

Monday, July 26, 2010

Debugging JavaScript memory leak in IE

I was recently working on one of the most difficult bugs in all of my years of programming. It involved a memory leak in IE8 caused by a couple of ASP.NET pages on a user's machine.

The first indication of the problem was the iexplore.exe process in the Windows Task Manager. Intermittently watching the 'Mem Usage' column on the 'Processes' tab, the memory usage reached over 2 gigabytes thereby significantly slowly down the user's machine. The rate of increase was about 9 MB every 30 seconds.

As with most web app bugs in IE, I checked to see if the problem was reproducible in Firefox. No leak. Next, I used two tools to help further identify the leaks: JavaScript Memory Leak Detector (IEJSLeaksDetector) and sIEve. Surprisingly, neither one indicated any memory leaks. This is when I knew this was not going to be easy troubleshooting much less fixing.

I tried running the app under IE7 compatibility view mode in IE8 but again no leak. Being skeptical of the reliability of this mode, I decided to try a true install of IE7 itself which required removing IE8 from the user's machine. Alas no leak. I also attempted from a different machine to connect to the web server running on that same user's machine to view the app (yes, one of the web app's features is to run as a local instance). Again no leak.

The problem web pages perform Ajax callbacks. Looking at the code, they were set to trigger the calls every 30 seconds. This was consistent with what was observed earlier with the rate of increase of memory usage. Naively, I thought could the ASP.NET Ajax Timer Control be broken?

I kept suspecting Microsoft's Ajax Timer Control which was helping to display a "Processing..." progress image to the user every 30 seconds. My ill-conceived rationale was that perhaps the code was using an old version of the Timer Control since the app was running on ASP.NET 2.0 and the code was originally written around the time when the ASP.NET AJAX framework was originally released.

Unfortunately, I temporarily fell under the spell of believing "Select is broken". This disillusion became painfully clear when I later confirmed that the specific Ajax framework was indeed the latest ASP.NET 3.5 web extensions for 2.0. Just to be sure, I created a standalone dummy web app with the same library that provides the Timer Control. Once again, as has been the pattern thus far: no memory leak.

More detailed information was needed. On the suggestion from another developer on the project, configured Task Manager with:
'Processes' tab -> 'View' -> 'Select Columns'
and added the following columns:
'Handles'
    'Threads'
    'USER Objects'
    'GDI Objects'  
Again, closely monitoring any changes, I noted that the GDI objects counts were increasing by 7~8 units every 30 seconds meaning this leak must somehow be graphics display related. Perhaps some image (or images) was not being removed or repeatedly added on each Ajax server request? (Possibly the aforementioned progress image?)

To further investigate the GDI objects findings, I used a few tools. Neither GDIUsage nor GDIObj provided any useful metrics (It's possible I might not have fully understood how to best use these.) However, GDIView allowed me to do snapshots of the memory usages of the GDI objects.

I manually copied the initial output displayed in GDIView and pasted that data into a text file. I subsequently waited until the data refreshed 30 seconds later and then copied that output into a separate text file. Finally, I performed a diff on the two files and it reconfirmed what was shown in Task Manager. The following text was the diff results:
Handle     Object  Kernel
  Type    Address  Extended Information
---------------------------------------------------------------  
0x86040059 Region 0xe2e68008 
0x3a0508e1 Bitmap 0xe45af558 Width: 1042, Height: 586 , Bits/Pixel: 32
0x29040972 Region 0xe55938d8 
0x3b040bb4 Region 0xe42f9868 
0x9a040bd1 Region 0xe1cd5738 
0xb3010bec DC 0xe3f9e9c8 
0x17300c6a Pen 0xe40dce88 Color: 0x02b0b0b0, Width: 0, Style: 0x00000000
0xe2050fb3 Bitmap 0xe2268840 Width: 1046, Height: 150 , Bits/Pixel: 16
0x133011fb Pen 0xe565c868 Color: 0x02b0b0b0, Width: 0, Style: 0x00000000
0x7004123c Region 0xe5685c18 
0x4e0415eb Region 0xe3031688 
0xc504172b Region 0xe183cdb8 
0x94041733 Region 0xe362f2b8 
0xae05180e Bitmap 0xe2c44840 Width: 1046, Height: 607 , Bits/Pixel: 16
0xfe01198b DC 0xe4c22008 
0x60011b7d DC 0xe28af008 

Clearly some bitmap was indeed being added repeatedly but the questions now were which one and why? The other developer helping out noted that the width of 1042 and height of 150 match the size of the web app within the browser. An important detail.

Recalling the purpose of the Ajax timer control was to display on both web pages a processing progress message and image (specifically a gif file), I decided to delve deeper into that area of the code. A 'progress' element containing the gif image is shown to the user via JavaScript. In that same JS function, an IFrame element is created and added to the 'Content' property of the 'progress' element. I noticed that the width and height of this IFrame was set to the document's height and width:
var progressIFrame = document.createElement("IFRAME");
    // ...
    progressIFrame.style.width = document.body.clientWidth;
    progressIFrame.style.height = document.body.clientHeight;
This was consistent with the results from the previously listed diff of the memory usage since the bitmap's dimensions were about the same size as the browser's viewport. Then, the very next line in the function struck me as strange:
progress.Content = progress.parentNode.insertBefore(progressIFrame, progress);
The return value of 'insertBefore' is a reference to the 'progressIFrame' element which it is then set to the 'progress' element's 'Content' property. Not only does it do this but it also adds it as a node sibling to the very same 'progress' element.

Why add the IFrame element to the DOM in two places? It was far from clear what the intent was for using the 'insertBefore' function if the IFrame element was already being added as part of the progress element itself?

Therefore, I changed it to directly set it and not bother with 'insertBefore':
progress.Content = progressIFrame;
and that stopped the memory leak!

Now, admittedly, I am not comfortably well-versed in JavaScript and this is one of those cases that I do not fully understand why the IE browser behaved the way it did in reaction to how the JavaScript is written.

Sometimes this is the outcome of debugging code (particularly when written by someone else). Although you come away learning some things you did not know before, you also might not know how or why something was broken to begin with or why the fix itself even worked.

Like writing code, debugging code is both a skill and art. However, it is certainly a different mindset.

Sunday, June 27, 2010

Project Euler solution # 1

I had an interest in doing some programming puzzles for the usual reasons: to practise and improve my logic skills, to explore new programming languages, and for simply to have...fun. The Python Challenge seemed appropriate when I started learning Python. I enjoyed doing the first few.

I then took a stab at one of the more popular puzzle websites, Project Euler (pronounced oil-er not you-ler which I incorrectly thought it to be.) This site not only encourages identifying efficient algorithms via your programming language of choice to solve the problems but strongly emphasizes math requiring more and more research as you advance to later problems.

Starting off with problem # 1:

Add all the natural numbers below one thousand that are multiples of 3 or 5.

Here is my first run, brute force attempt at the solution using Python:
divisors = [3, 5]
multiples = []
for i in range(1, 1000):
    del multiples[:]
    for divisor in divisors:
        if i % float(divisor) == 0:
            multiples.append(divisor)
    if multiples:
        print i,' is a multiple of ',', '.join([str(multiple) for multiple in multiples])

The earlier code solved the problem but, shortly after churning it out, I discovered that it did not offer the expected format of the answer. Therefore, re-worked the code to do so:
multiples = []
for i in range(1, 1000):
    if i % 3 == 0 or i % 5 == 0:
        multiples.append(i)

print sum(multiples)           

While this returns the correct value of 233168, the structure of the code could have some pythonic polish added to it. A dab of list comprehensions does the job:
print sum([x for x in range(1, 1000) if x % 3 == 0 or x % 5 ==0])

In the spirit of one reason why I'm doing these puzzles, here is a solution in C:
main()
{
  int sumOfMultiples = 0;
  int i;
  for(i = 1; i < 1000; i++)
    {
      if (i % 3 == 0 || i % 5 == 0){
          sumOfMultiples += i;         
      }
    }
  printf ("%i \n", sumOfMultiples);
}   

Monday, May 31, 2010

Cross-browser compatibility

My first true deep dive into heavy JavaScript programming was working on a project that required adding Firefox support for a web application that only targeted Internet Explorer. The web application was originally written for IE6 and therefore contained some hairy JavaScript.

I experienced firsthand the same rite of passage as millions of web developers around the world. Fortunately, adding support for Firefox also meant that the web app no longer needed to support IE6 (only IE7+) so fixing the JavaScript to be cross-browser compatible became a bit more reasonable and sane.

Now, some snippets collected for these changes in no particular order:

# 1

Replacing all references to the DOM Level 1 function
top.frames['myId']
, which gave Firefox much trouble, with the DOM Level 2 function:
document.getByElementId('myId')


# 2

Replace the function 'removeNode':
if (x)
{
    x.removeNode();
}
with a conditional check that uses the Firefox friendly function 'removeChild' if parentNode is defined (otherwise fallback on 'removeNode'):
if (x)
{                  
    if (x.parentNode) 
        x.parentNode.removeChild(x);  // Firefox                  
    else
        x.removeNode(); // IE
}

# 3

The 'innerText' property does not work in Firefox but it does in IE. Instead, Firefox does recognize 'textContent' serving the same purpose. Again, use another if-else statement checking if the target element exists:
function setText(elem, textValue)
{
    if (elem.textContent || elem.textContent == "")
    {
         elem.textContent = textValue; // Firefox
    }
    else 
    {
         elem.innerText = textValue; // IE
    }
}

# 4

Dot notation for defining functions is another area where JavaScript errors emerge in Firefox:

"...missing ( before formal parameters..."
function window.onDoSomething()
{
 // do some stuff
}
To fix is to swap around the 'function' keyword:
window.onDoSomething = function()
{
 // do some stuff
}

# 5

One of the web pages had a character that used the Webdings (TrueType dingbat) font for an expressive, functional symbol. It rendered incorrectly (and confusingly) in Firefox. Substituting the equivalent Unicode character resolved the discrepancy.


# 6

All AJAX calls involved the following IE6 object:
var xmlHttp = new ActiveXObject('Microsoft.XMLHTTP');
As mentioned, with no need for supporting IE6 (something web developers dream of someday being true for all the of internet) every instance of the previous line of code is fully replaced with:
var xmlHttp = new XMLHttpRequest();
Certainly, one of the more satisfying cross-browser changes.


# 7

Firefox does not support referencing global event objects specifically 'window.event' and when encounters JavaScript code that attempts to do so it responds with this error message:

window.event is not defined.

Instead, it is necessary to pass the event object as an argument via a function's parameter:

    function myFunction(e) // <-- add 'e' as a parameter for the global event object
    {
        if(!e) e = window.event // if e is undefined then set e using IE event object
        // other code
    }

    <button onclick="myFunction(event);">test events</button>

# 8

A web page had a file browser functionality to attach a file for upload to the server. The 'onclick' event handler for this element's tag and type
<input type="file" ...
was coded to be programmatically triggered. The reason for this was to allow for the user to type in and edit the free form text of the file path and then the JavaScript would create the 'input' and then fire the event on the user's behalf.

Firefox does not allow this requiring the user to manually click on the tag since the file path text is read-only and can not be edited. It is considered a potential security flaw hence the restriction. The code needed to be rewritten to have the user directly fire the event and open the file browser.


# 9

An html table on a page contained rows with hidden nested rows functioning as a tree-like grid. These top level rows when clicked toggled between the style of
display:none
when hiding its children rows and then used
display:block 
when showing the rows.

In Firefox, the rows do not align properly when made visible with 'block' display style. The premature solution was to replace 'block' with
display:table-row
which worked for both IE8 and Firefox.

However, I later discovered that this type of display was not supported in IE7. Instead, substituted the equivalent of no display style at all using empty string
rowObject.style.display = ''
to show hidden rows. Apparently, each browser knows by default how to appropriately render the rows without the need to be specific in the html.


# 10

Consider a deeply nested event firing and then needing to prevent it from triggering other event handlers further up the DOM hierarchy. In IE,
window.event.cancelbubble
should take care of this. Firefox, of course, does not recognize this command. Instead, one must use the
event.stopPropagation
function to exercise the same control over the scope of an event.

To ensure coverage across the different browsers, do this:
function doSomething(e)
{
 if (!e) var e = window.event;
 e.cancelBubble = true;
 if (e.stopPropagation) e.stopPropagation();
}

# 11

Some JavaScript code was not executing at all. No clear indications why the function was not defined. It turns out that using the term 'jscript' as part of the 'type' attribute in the 'script' tag:
<script language="javascript" type="text/jscript" ...
is , not surprisingly, recognized only in IE and not in Firefox. All instances of 'jscript' were replaced with 'javascript':
<script type="text/javascript" ...
This cross-browser issue caused so much grief for such a simple fix. I spent way too much time figuring it out. When I read:

"...Nevermind, I think I found it. I inherited the code and just noticed that the original programmer had specified JScript rather than Javascript as the script language..."

I glanced over to my aspx page and my eyes immediately saw that exact error. Unbelievable.


# 12

Another function not defined in Firefox but used in IE:
window.attachEvent
In Firefox, use this instead:
window.addEventListener
The cross-browser code might look like this:
eventName = 'load';

if (window.addEventListener) // Firefox
{
  window.addEventListener(eventName, myFunction, false);
} 
else if (window.attachEvent) // IE
{
  window.attachEvent('on' + eventName, myFunction);
}
(Note that IE requires the prefix "on" for the event name while Firefox does not.)

All of the above applies to IE's
window.detachEvent
For Firefox, use
window.removeEventListener


# 13

Some image icons when hovering over with the mouse were expected to show tooltip text. However, no tooltips shown in Firefox with the following:
<input type="image" disabled="disabled" text="Hi there"...
Instead, replaced the 'input' element tag with an 'img' element:
<img text="Hi there" src="disabled.gif"

# 14

An html table needed to be dynamically resized by changing it's style. The original IE-only code:
tableObject.style.left=400
    tableObject.style.top=400
No effect in Firefox (the size remained the same), so needed to explicitly add the unit of measurement "px":
tableObject.style.left=400 + "px"
    tableObject.style.top=400 + "px"
Also applies to 'height' and 'width':
tableObject.style.height="55px"
    tableObject.style.width="33px"


# 15
Dynamically adding some new html into a page relied on 'insertAdjacentHtml':
document.body.insertAdjacentHTML('AfterBegin', '<div>foo</div>')
Worthless in Firefox (at least until HTML5 is supported) so fall back on 'insertBefore':
elementHtml = '<div>foo</div>';

if (document.body.insertAdjacentHTML)
{
     document.body.insertAdjacentHTML('AfterBegin', elementHtml)
}
else
{
    element = document.createElement("div");
    element.innerHTML = elementHtml;
    document.body.parentNode.insertBefore(elem, document.body);    
}
(Orignally, used
document.body.insertBefore(element, document.body.childNodes[0])
but that seemed to cause the event (specifically the 'onload' event of an image) to fire repeatedly in Firefox so changed it to use the one listed above.)


# 16

The mouse's position was necessary to figure out where to render a dynamically injected image. In IE, to determine the X and Y coordinates relative to the web page document:
window.event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft
    window.event.clientY + document.body.scrollTop + document.documentElement.scrollTop
Functions 'client<X|Y>' tell you the "viewport" position of the mouse which is a smaller, overlapping portion of the entire document but not a true subset of it. To obtain the document's actual mouse position, you need to add to these position values the scroll values by using the other functions shown above. Specifically,
document.body.scroll<Left|Top>
are the older (i.e. quirksmode) DOM syntax to retrieve the scroll values while
document.documentElement.scroll<Left|Top>
are the more modern standard approach. Depending on the browser only one of these will have the actual value while the other will equal zero. Therefore, it's safer and relatively harmless to include both.

In stark contrast, Firefox simply uses these:
e.pageX
    e.pageY
For a comprehensive code snippet that works across most major modern browsers:
function doSomething(e) {
 var posx = 0;
 var posy = 0;
 if (!e) var e = window.event;
 if (e.pageX || e.pageY)  {
  posx = e.pageX;
  posy = e.pageY;
 }
 else if (e.clientX || e.clientY)  {
  posx = e.clientX + document.body.scrollLeft
   + document.documentElement.scrollLeft;
  posy = e.clientY + document.body.scrollTop
   + document.documentElement.scrollTop;
 }
 // posx and posy contain the mouse position relative to the document
 // Do something with this information
}


# 17

To cancel an event just for the local scope only but not stop the event from bubbling up to the rest of DOM tree, in IE set
e.returnValue
to false.

For Firefox, use:
e.preventDefault
Cross-browser function:
if(e.preventDefault)
  {
    e.preventDefault();    // Firefox
  } 
  else
  {
    e.returnValue = false;    // IE
  }

One last (thought) snippet

While extremely beneficial being exposed to JavaScript's historical client-side scripting messiness in different browsers, next time when faced with cross-browser quirkiness I'd use a library like jQuery for simplified and easier web development.

Friday, April 30, 2010

Running Mono C# REPL on Windows

Being a big fan of programming language REPLs and command-line consoles, I have awaited one for C# that I can easily install and comfortably use for lightweight validation of C# syntax and for exploring its language features. Originally, Snippet Compiler had filled that role and then replaced with LINQPad but neither one is a REPL.

Fortunately, Mono, the open source project for .NET and C# that offers cross OS platform support especially for Linux and Mac, does have an interactive shell (CsharpRepl) for evaluating C# statements and expressions. Since Mono also runs on Windows, I downloaded and installed the latest Mono release 2.6 on my Windows development machine.

Once installed, to run the C# REPL simply:

  1. Select Start ->; All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
  2. At the command prompt, type "csharp"

The first step just adds Mono's bin directory to your environment PATH for the current shell session. (Alternatively, you can navigate via the command line to the Mono bin directory and directly run the file, csharp.bat.)

The C# REPL works if used within the Windows shell, cmd.exe (a.k.a. "command prompt") but with some caveats. The first immediate one is the command prompt text "csharp >" is not displayed making it a bit disorienting to use. It's difficult to distinguish between the input and the output of your expressions. [Update: This bug was subsequently fixed and it is now available with the version 2.6.7 release.]

Another is no autocomplete functionality but this feature is only available in Mono's GUI command console, 'gsharp'. GSharp requires an additional install of the mono-tools package available on the Windows platform download page under the link named "Gtk# for .NET". Once installed, to launch gsharp:

  1. Start -> All Programs -> Mono 2.6.1 for Windows -> Mono-2.6.1 Command Prompt
  2. c:\> gsharp

To activate autocomplete, type in part of a word and then hit <TAB>. Sometimes auto-completing words is slow in gsharp particularly if it has to search a large set of libraries. For example, typing the text "using Sys" and then <TAB> causes hanging since 'System' is the most top level .NET lib.

I decided to stick with using gsharp (a.k.a. the "C# InteractiveBase Shell"?) over csharp plus cmd.exe combo not only because of the autocomplete feature but because it also does display a "csharp >" prompt.

With those two issues resolved in gsharp, I continued to explore how the csharp REPL performed and behaved. The most striking deficiency I then encountered was when typing a statement containing invalid syntax, it did not show any output results. This was surprising since it goes against what I consider to be one of the hallmarks of a good REPL: immediate feedback not just on command/code that evaluated successfully but on things that failed to evaluate properly. Strange the lack of output...almost as if it was missing the 'Print' in REPL.

With continued use, I noticed in the examples found in the Mono REPL documentation that each expression or statement requires the ";" character at the end of it to produce any visible output. Otherwise, it gets ignored. I was expecting the same behavior found in the Visual Studio's Immediate Window where ";" is not always required. Not sure what the advantage of having to always type ";" (other than as a constant reminder that you are using a C based language in a REPL). Just seems like an extra unneeded keystroke.

However, reading more of the REPL docs, it implies multiple declarations can be made on a single line using ";" as a delimiter:

csharp> var a  = "why so many semi-colons?"; 5; "more stuff!";
"more stuff!"
csharp> a;
"why so many semi-colons?"
csharp>

All three statements get evaluated but only the last one ("more stuff!") is printed to the screen.

The docs also explicitly state the inverse: one declaration ending with ";" can be spread across multiple lines:
"...Statements and expression can take multiple lines, for example, consider this LINQ query that displays all the files modified in the /etc directory in the last week. The prompt changes from "csharp" to " >" to indicate that new input is expected..."
and
"...Multi-line input...If your code does not fit in a single line, you can enter expressions in multiple lines. The shell will not execute the code until a valid expression has been entered or a syntax error is flagged. A special prompt is shown to indicate that ics is waiting for input..."

Although the docs states that multi-line input is supported, it does not seem to be true of my current install on Windows. On Linux, I can do this:

csharp> var list = new int [] {1,2,3};
csharp> var b = from x in list
   >    where x > 1
   >    select x;
csharp> b;

On Windows, however, the special indented continuation prompt "  >" never appears when a new line is returned if the ";" character is not included. This is unfortunately a notable flaw in the REPL tool on the Windows platform.

In addition to the online documentation, another source describing the more common commands is available in the REPL itself. Just type "help;":
"Static methods:
Describe(obj)      - Describes the object's type
LoadPackage (pkg); - Loads the given Package (like -pkg:FILE)
LoadAssembly (ass) - Loads the given assembly (like -r:ASS)
ShowVars ();       - Shows defined local variables.
ShowUsing ();      - Show active using decltions.
Prompt             - The prompt used by the C# shell
ContinuationPrompt - The prompt for partial input
Time(() -> { })    - Times the specified code
quit;
help;
TabAtStartCompletes - Whether tab will complete even on emtpy lines
"
Of course, a couple of these commands exhibit some quirks. If type 'ShowUsing();' it does not display anything in the console although it is expected to do so (it behaves like this on Linux). After trying the command several times, I looked at the original command prompt window from which gsharp launched and saw the results of the command showing in there. The same was true with 'ShowVars()'. Recommend keeping the command prompt console in view while using gsharp to see any output piped outside of it. (The issue appears to been logged at the mono project as a bug.)

Perhaps to truly escape all of these OS specific limitations, I might be better off running Mono's REPL within a Linux VM on Windows. However, this approach negates the benefits of a cross-platform framework that Mono aspires to be.

Despite these minor difficulties, Mono's C# REPL has been a nice addition to my .NET development toolbox. It has proved useful when I needed a deeper understanding of how delegates and lexical closures behave in C# and when figuring out how to do list comprehensions in C# using List<T>.ConvertAll instead of LINQ. It provides a quick, frictionless way of observing and interacting with the functionalities of C# and the .NET libraries.

Tuesday, March 30, 2010

Database schema changes unit tested using TSQLUnit

How does one test the existence of a primary key (PK) constraint belonging to a table in a database? Simple, right? Just write a test that intentionally violates that constraint. One's initial impulse would be to write a test inspecting the data contained within the PK's table. This approach is sensible and can be viewed as the conventional state-based style of testing.

Let's try it. The following test using TSQLUnit attempts to insert in a table a new row with the same value for its primary key as another existing row's PK:
create procedure dbo.ut_SubProduct_PkConstraint
as
begin
    declare @failMessage        varchar(200),
            @err                int,
            @primaryKeyError    int

    set @primaryKeyError = 2627
           
    /* RUN TEST */
-- grab row already in table and try to re-insert it.
    insert into dbo.SubProduct    
        select top 1 sp.*
        from dbo.SubProduct sp
   
    set @err = @@error       

    /* ASSERT TEST */
    if  @err <> @primaryKeyError
        begin
            set @failMessage = 'PK constraint not defined.'
            exec tsu_failure @failMessage
        end
end
The above code will not work as a good test because error messages regarding the failure to insert a row with a duplicate PK will occur that can not be suppressed in TSQLUnit's test runner (as viewed in the 'Results' window in Sql Server Management Studio). (Even with some not-too-in-depth research, I could not find a means to hide or suppress these error messages using TSQL.)

Instead, it can be tested more cleanly using SQL Server's info schema views:
create procedure dbo.ut_Product_PrimaryKey
as
begin
    declare @failMessage        varchar(200),
            @tableName          varchar(40),
            @primaryKeyColumn   varchar(40)

    set @tableName           = 'Product'
    set @primaryKeyColumn    = 'ProductID'
           
    if not exists
    (
        select      c.table_name, c.column_name, c.data_type
        from        information_schema.columns c
            inner join information_schema.key_column_usage kcu
                    on c.table_name = kcu.table_name and c.column_name =
                       kcu.column_name
            inner join information_schema.table_constraints tc
                    on tc.table_name = kcu.table_name and tc.constraint_name =
                       kcu.constraint_name and tc.constraint_type = 'PRIMARY KEY'
        where       c.table_name = @tableName and kcu.column_name = @primaryKeyColumn
    )
    begin
        set @failMessage = 'PK constraint not defined for ''' + @tableName + '.' + @primaryKeyColumn + ''''
        exec tsu_failure @failMessage
    end
end
That's it. You now have a test that handles primary key constraints.

Of course, this is not the last and only time where primary keys will require testing. While the above sproc does a satisfactory job, it is not reusable for any other tables. Let's refactor it into a more generic "Assert" sproc in an xUnit style:
create procedure dbo.tsux_AssertPrimaryKeyExists
/* This is an extension to the TSQLUnit framework. */
(  
    @tableName            varchar(40),
    @keyColumn            varchar(40),   
    @failMessage          varchar(255)=null   
)
as
begin
    if not exists
    (
        select      c.table_name, c.column_name, c.data_type
        from        information_schema.columns c
            inner join information_schema.key_column_usage kcu
                    on c.table_name = kcu.table_name and c.column_name =
                       kcu.column_name
            inner join information_schema.table_constraints tc
                    on tc.table_name = kcu.table_name and tc.constraint_name =
                       kcu.constraint_name and tc.constraint_type = 'PRIMARY KEY'
        where       c.table_name = @tableName and kcu.column_name = @keyColumn
    )
    begin
        if @failMessage is null
            set @failMessage = ' PK constraint not defined for ''' + @tableName + '.' + @keyColumn + ''''
        exec tsu_failure @failMessage
    end
end
Your actual test becomes more compact and easier to understand:
create proc dbo.ut_Product_PrimaryKey
as 
begin
    exec dbo.tsux_AssertPrimaryKeyExists
        @tableName                  = 'Product',
        @primaryKeyColumn           = 'ProductID',
end
Any verification of pure schema changes such as the creation of new tables, columns, constraints, etc. via unit tests is better served using SQL Server's system tables and views to query the necessary meta information. This has proven to be more preferable than performing data centric state based tests (This technique reminds me a little of using reflection in .NET to do testing)

The earlier test for primary keys can be also applied to foreign key constraints as well. However, it requires some additional pieces to validate including the table and column being referenced. After (once again) finding the suitable tsql needed via an online search, here is the test:
create procedure dbo.tsux_AssertForeignKeyExists
/* This is an extension to the TSQLUnit framework. */
(
    @tableName            varchar(40),
    @foreignKeyColumn     varchar(40),
    @referenceTable       varchar(40),
    @referenceColumn      varchar(40),   
    @failMessage          varchar(255)=null   
)
as
begin
    if not exists
    (
        /*
            This is modified version of the tsql query used to retrieve foreign key info
            courtesy of:
                http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_22952666.html
        */

        select
            object_name(fkeyid)     as TableName,
            a.name                  as FKColumn,
            object_name(constid)    as FKConstraint,
            object_name(rkeyid)     as ReferenceTable,
            b.name                  as ReferencedColumn
        from sysforeignkeys f
            inner join syscolumns a on a.id = f.fkeyid and a.colid = f.fkey
            inner join syscolumns b on b.id = f.rkeyid and b.colid = f.rkey
        where
            fkeyid                        = object_id( @tableName )
            and a.name                    = @foreignKeyColumn
            and object_name(rkeyid)       = @referenceTable
            and b.name                    = @referenceColumn
    )
        begin
            set @failMessage = 'FOREIGN KEY does not exist for ''' + @tableName + '.' + @foreignKeyColumn  +  ''''
            exec tsu_failure @failMessage
        end
end
Now the new unit test would plainly look like this:
create procedure dbo.ut_Product_ForeignKeys
as
begin
    exec dbo.tsux_AssertForeignKeyExists
        @tableName            ='Product',
        @foreignKeyColumn     ='CategoryID',
        @referenceTable       ='Category',
        @referenceColumn      ='CategoryID'   

end
Database Testing: How to Regression Test a Relational Database, which details areas of any database that should be tested, had been an influence on developing these types of data definition language (DDL) tests. As an example, referential integrity is mentioned as being important area to test. On the surface, it seems a bit overkill to set up tests for PKs and FKs. However, even superfically minor data errors can be costly.

I was once tasked with expanding the size of a core primary key column that had multiple dependencies to other tables (including views and sprocs). As expected, to make the change required temporarily dropping the PK and FK constraints on those other tables and then add them back after applying the change.

Herein lies the risk. What if the "adding back" part was accidentally forgotten and not included in the change script? What if it was temporarily commented out with the intention to uncomment it later but overlooked? Allowing a deficient, regression-inducing script to rollout into a live production environment would be poor software development.

What automated unit tests provide in this situation is the insurance and safety net that the constraints are less likely to be missed or forgotten. They enforce the existence of those key constraints and firmly establish them as requirements for the database. It further instills greater confidence to make these sorts of changes by providing immediate feedback during development (and not much later) if the constraints are not set.

Another situation where unit testing using meta data came in handy was increasing the data type length of a column. Initially, when the size of varchar for a few columns needed to increase, I had some data heavy tests performing row insertions. These tests were fragile since they'd break the TSQLUnit test runner itself if a test inserted data larger than the expected size. Instead, I created a generic assert stored procedure that used the system sproc, 'COL_LENGTH':
create procedure dbo.tsux_AssertColumnLength
/* This is an extension to the TSQLUnit framework. */
(
    @tableName            varchar(40),
    @columnName           varchar(40),
    @expectedLength       smallint,
    @failMessage          varchar(200)=null
)
as
begin
    declare @actualLength        smallint

    select @actualLength = COL_LENGTH(@tableName, @columnName)

    if @expectedLength != @actualLength
        begin           
            set @failMessage = 'Column length for ''' + @tableName + '.' + @columnName  +  ''' does not match expected value.'
            exec tsu_failure @failMessage
            print 'Expected: '    + cast(@expectedLength as varchar(3))
            print 'Actual: '    + cast(@actualLength as varchar(3))
        end
end

Again, reusable and reliable code which avoids relying on sql compiler errors to indicate test failure.

Other examples of generic asserts for columns aside from length:

* tsux_AssertColumnExists
* tsux_AssertColumnDataType

Also, some other areas using test assertions:

* permissions on an object (quite important and often overlooked until too late)
* stored procedure parameter lengths
* existence of tables, views, and other similar database objects
* schemabinding on views

What's more is that these types of tests can be easily code generated. For example, if database changes included adding new columns, then unit tests can be generated by extracting the columns' meta data (e.g. name, datatype, length, etc.) as defined in a sql script (or even from an xml file or spreadsheet). The same can be done with existing data objects and structures requiring DDL changes but the meta data can be pulled from the database's system tables/views. In this situation, you gain some automatic test coverage for your current schema before attacking it with alterations.

Not sure if any of the techniques detailed earlier could be applied to check constraints (e.g. inserted/updated datetime value should not be greater than today's date, etc.). Perhaps, check constratins can be sufficiently managed with simple, direct unit tests using data rather than using meta data. (Although it could be argued that the logic for most check constraints should exist in the application code and not in the database. However, in practise, this is not always the case.) For now, without an immediate need, it will remain speculative.

This is likely my last post on TSQLUnit. In the future, my data access tests will probably be created in and executed from the application code rather than on the SQL Server side. However, if I do find myself in a scenario where database-only unit tests are needed, I'd probably try out T.S.T. the T-SQL Test Tool since it has built-in assert functions.

Wednesday, February 24, 2010

Software developer: an asset not a cost

I was quoted last year in a post, Convincing the Boss to Pay for Developer Training:

"...For example, software developer Ray Vega points out, "The 'culture' of the company is dedicated (sic) by how it makes money and who is responsible for helping to making that money." In general, he says, software companies whose product is technology-based tend to be better at providing and paying for skill improvement resources for tech employees. When the technology workers training is closely related to company revenue, it's easier to get the boss to listen. However, Vega adds, "If you work on an application that has no direct association with how the company makes money (for example, an internal time tracking application for an insurance company) then it will certainly be an uphill battle."


My response was based on not just my own work experience but also on an old Joel Spolsky article Five Worlds (which was provided to the author in my original response to her research on the topic). The "world" you write code for makes a significant difference in the overall health of your professional career beyond just training costs.

Most good programmers probably don't need formal "training" focused on a vendor specific technology, platform, or framework with a potentially short shelf life. They'd more likely learn on their own by creating and working on a side project or on a simple prototype specifically for that purpose. However, one exception is if the training class included like-minded individuals with whom one can collaborate and reciprocally learn from. Sadly, these are rare to find and difficult to vet prior to investing one's time in a chosen course.

That said, sometimes it doesn't hurt to be exposed to informational seminars, conferences, or coursework that cover the enduring fundamentals of software development (or even computer science) that people tend to forget or simply don't know.