Friday, February 27, 2009

It's True (And Not False): Assert Equality in TSQLUnit

When working with xUnit style frameworks like NUnit, it is generally expected to find support for assertions. Asserts are an indispensable tool in any testing process. Unit testing at its core is simply verifying whether something has occurred or not occurred i.e. checking if the state has changed marking it as either true or false. Built-in assert syntax provides programmers a means to perform this level of testing repeatedly and consistently. One of the more common assertions is to compare the values of two items, such as variables or objects, sometimes referred to as equality asserts. As an example, here is C# test code using NUnit to test a method that simply adds two arguments:
// some static class
public static int Add(int firstItem, int secondItem)
{
return firstItem + secondItem;
}

[Test]
public void Verify_sum_of_5_and_3_equals_8()
{
Assert.AreEqual(Add(5,3), 8);
}
Imagine my disappointment to discover the absence of equality assert functionality in TSQLUnit. The framework inexplicably does not have any native support for them. (Perhaps this might be because the project has not been active for a very long time.) Instead, you have to construct your own tailor-made assertions outside of the framework itself.

While using TSQLUnit without the aid of asserts, a definite pattern emerged as tsql plumbing code rapidly began to replicate in numerous tests. Here is an example of a unit test, plagued with the same identical code found in multiple places, whose purpose is to verify whether a 'ProductNumber' column has been successfully updated:
create procedure dbo.ut_CanUpdateProductNumber
/* UNIT TEST */
as
begin
declare @expectedProductNumber varchar(40),
@actualProductNumber varchar(40),
@currentAccountID varchar(16)

set @expectedProductNumber = '1234567890'

-- find a account to test
select top 1 @currentAccountID=AccountNbr
from dbo.Account

/* RUN TEST */
-- update product number
update dbo.Account
set ProductNumber = @expectedProductNumber
where AccountNbr = @currentAccountID

-- get updated product number
select @actualProductNumber=l.ProductNumber
from dbo.Account l
where l.AccountNbr = @currentAccountID

/* ASSERT TEST */
if @actualProductNumber != @expectedProductNumber
begin
exec tsu_failure 'The product number is not the same.'
print 'Expected: ' + @expectedProductNumber
print 'Actual: ' + @actualProductNumber
end

end
The duplicated code is the conditional 'if' block at the end of the stored procedure where the assertion is executed using 'tsu_failure', the obligatory proc call to the TSQLUnit framework that transforms your tsql code into a real live unit test. All test sprocs are built around this critical function. Unfortunately, 'tsu_failure' does not handle actual comparisons between two values, but only after the comparison has been made. It was not designed to recognize when value comparisons are useful or required. Instead, the surrounding test code is responsible for making that evaluation, in this case, using a custom conditional statement not originating from any TSQLUnit function.

In addition, being accustomed to seeing in NUnit test messages that display the detailed results of value comparisons (i.e. expected against actual), print statements were added to the test procs to simulate that same text. For example, the following is what would be shown if the aforementioned test were to fail:
The product number is not the same.
Expected: 1234567890
Actual: 0987654321
Although a welcomed improvement in the feedback provided by the test runner's results, I found myself repeatedly injecting that same structure over and over in numerous other tests.

When this form of repetition occurs, a strategy can be adopted of either (1) continuing copying and pasting code, (2) using code generation, or (3) formulating and developing some reusable code component to manage the duplication. With # 1 and # 2 being obvious maintenance sinkholes draining away any value earned from the test code, implementing # 3 was a more sensible choice.

To fight off test code rot, the 'if' block was refactored and encapsulated into a separate, shareable stored procedure (think Extract Method). Nothing extravagant but quite effective:
create procedure dbo.tsux_AssertAreEqual
/* This is an extension to the TSQLUnit framework. */
(
@expected varchar(8000),
@actual varchar(8000),
@failMessage varchar(255)
)
as
begin
if @actual != @expected
begin
exec tsu_failure @failMessage
print 'Expected: ' + @expected
print 'Actual: ' + @actual
end
end
Calling this new proc provides the familiar, sought-after "Assert.AreEqual" functionality found in NUnit and in a lot of other test frameworks. The old 'if' block in the original test was subsequently replaced with the new assert proc:
create procedure dbo.ut_CanUpdateProductNumber
/* UNIT TEST */
as
begin
/*...unaltered code...*/

/* ASSERT TEST */
exec dbo.tsux_AssertAreEqual
@expectedProductNumber,
@actualProductNumber,
'The product number is not the same.'

end
Now that we have a general utility assert sproc for the varchar type, we still have other data types, including int and datetime, that can also benefit from assertions of their own. Since TSQL does not support a flexible language feature like C# type generics for its stored procedures, creating sprocs for each data type is the only clear option to expand this functionality beyond vachar:
tsux_AssertDatesAreEqual
tsux_AssertIntsAreEqual
I can understand why the creator of TSQLUnit might have not initially built asserts into the framework since it requires building one for each every kind of data type in TSQL. Therefore, in its place, the burden falls on the user (i.e. me) to add additional asserts to the test code base as the need arises.

One kind of assert involving condition testing that might be interesting to implement but I am uncertain if it is remotely doable is this:
set @sqlConditionToEvaluate = (@expectedColor = 'BLUE'
AND @expectedSize = 23 OR StartDate between '1/1/11' and '2/2/22')
exec tsux_AssertIsTrue(@sqlConditionToEvaluate)
or more concisely:
exec tsux_AssertIsTrue(@expectedColor = 'BLUE'
AND @expectedSize = 23 OR StartDate between '1/1/11' and '2/2/22')
Maybe this could be achieved using dynamic sql and with storing each condition to verify within a 'TABLE' data type variable (functioning as an array) that can be looped checking each one to be true or false. However, implementing complex asserts to this extreme extent is a strong indication that TSQLUnit might no longer conceivably be the appropriate tool to write unit tests. It might be preferable to consider alternate unit testing frameworks that operate entirely outside of the database using a language other than TSQL that is better equipped for elaborate conditions and logic flow.

Friday, January 30, 2009

Paging in ASP.NET using NHiberate

NHibernate, the object-relational mapping (ORM) framework for .NET, supports custom pagination for collections. It provides a potential alternative to the built-in paging mechanism and native support found in ASP.NET GridView web controls. NHibernate exposes in the API for IQuery and ICriteria two methods, SetFirstResult and SetMaxResult, that can be used to enable paging:

Collections are pageable by using the IQuery interface with a filter:

IQuery q = s.CreateFilter( collection, "" ); // the trivial filter
q.setMaxResults(PageSize);
q.setFirstResult(PageSize * pageNumber);
IList page = q.List();

Adding Paging to the Base DAO

The design and architecture of my project, where NHibernate style pagination shall be introduced, was deeply influenced by Billy McCafferty's NHibernate Best Practices with ASP.NET resulting in the proliferation of Data Access Objects (DAO) throughout the guts of the application. Each DAO maps one-to-one to a single matching table in the database.

For example, a 'Task' table would have a corresponding 'TaskDao' in the data access layer (DAL) of the application. All of these DAOs inherit from the same base class 'GenericNHibernateDao' responsible for containing commonly shared code including managing NHibernate sessions and providing generic methods for summoning a specific persisted instance by ID and for saving/deleting an existing instance.

The initial step to implement paging was adding the following members to the aforementioned base class 'GenericNHibernateDao':

public abstract class GenericNHibernateDao : IGenericDao
{
public int PageSize
{
get { return _pageSize; } set { _pageSize = value; }
}

public int PageNumber
{
get { return _pageNumber; } set { _pageNumber = value ; }
}

protected int GetFirstResultPosition()
{
return _pageSize * (_pageNumber - 1);
}

protected void SetPagingFor(IQuery query)
{
query.SetFirstResult(GetFirstResultPosition());
query.SetMaxResults(_pageSize);
}

protected void SetPagingFor(ICriteria criteria)
{
criteria.SetFirstResult(GetFirstResultPosition());
criteria.SetMaxResults(_pageSize);
}

/*
other non-paging related members...
*/
}

The property 'PageSize' gets/sets the number of instances expected to be displayed on a web page for a specific strongly typed collection. Essentially, it handles how many rows to return for a embedded control (such as a GridView) on the page. This property is intended to be internally consumed by NHibernate's 'SetMaxResults' method belonging to IQuery or ICriteria. For example:

IQuery query = Session.CreateQuery();
query.SetMaxResults(_pageSize);

'PageNumber' specifies the set of multiple instances to be returned and displayed on a web page as identified and grouped by a page sequence numeric value (This is the equivalent of 'PageIndex' property for GridViews). For example, if you had a total of five pages worth of data rows then displaying the second page would require setting the page number value to '2' (e.g. _dao.PageNumber = 2). Just as with 'PageSize', this property is intended to be used by the method 'GetFirstResultPosition' as will be explained next.

The protected method 'GetFirstResultPosition' calculates the actual row at which to start paging based on the values provided by 'PageSize' and 'PageNumber'. This method's return value is expected to be passed to NHibernate's 'SetFirstResult' method, once again, part of IQuery or ICriteria. For example:

IQuery query = Session.CreateQuery();
query.SetFirstResult(GetFirstResultPosition());

The overloaded method named 'SetPagingFor' performs the actual paging functionality via the 'SetFirstResult' and 'SetMaxResult' methods of IQuery and ICriteria. (As an aside, the use of IQuery to build and execute HQL is much more common on this project in comparison to the almost non-existent use of ICriteria).

The base class 'GenericNHibernateDao' was also modified to have one of its existing methods 'GetAll' call 'SetPagingFor'. (The 'GetAll' method simply returns a list of all strongly type objects in the database without any specified criteria or filtering):

// GenericNHibernateDao class
public IList<T> GetAll()
{
ICriteria criteria = Session.CreateCriteria(persitentType);
SetPagingFor(criteria); // this is newly added!
return criteria.List();
}

As it shall be made clear later, this new line of code will optionally provide paging functionality when 'GetAll' is requested, if needed, but not required per se.

Applying Paging Functionality in the DAOs

Now that the base class 'GenericNHibernateDao' has been updated to manage paging, any of its derived DAO classes are instantly equipped to perform paging themselves. To actually invoke the paging functionality for any of the DAOs, simply set the appropriate values for page size and page number as shown in this example for the 'TaskDao' class:

// In context (such as a Presenter or Controller class
// part of an MVP/MVC applied framework)
TaskDao _taskDao = new TaskDao();
_taskDao.PageSize = 20;
_taskDao.PageNumber = 5;
IList<TaskDao> list = _taskDao.GetAll();

Without paging, 'GetAll' would have returned something in the neighborhood of 100 or so rows. With paging, the returned list will instead be only 20 rows starting at row (i.e. position) # 80. While a hundred rows might not sound too substantial, larger sets of data can have a more noticeable effect on your application's day-to-day operations if your table contains tens or hundreds of thousands of rows. Your performance will be progressively impacted as your application scales with more data.

On the other hand, NHibernate's paging will significantly decrease the size of your result set. This is in stark contrast to the default behavior of the existing paging available in any GridView control. If this native functionality of the control is used, it will return all rows from the database and then page them in memory. As mentioned earlier, this can lead to slower performance as your data grows. More on this later.

If, for any reason, paging is not essential for a particular web page in possession of a control bound to a strongly typed list (for example,a very small static list of data) then setting the page size and number properties is not required at all. Simply call 'GetAll' by itself disregarding the 'PageSize' and 'PageNumber' properties and the DAO should return all rows found in the associated database table. What makes this possible is that the default values for those two paging properties are formally declared in the DAO base class to behave as expected for "non-pageable" collections:

public abstract class GenericNHibernateDao : IGenericDao
{
protected int _pageSize = -1; // default for unlimited page size
protected int _pageNumber = 1; // default for first item in collection

// more members...
}

Typically, a DAO might have other custom methods that return more narrowly focused (i.e. filtered) lists of typed objects than what 'GetAll' offers. For these other DAO methods, the same pattern can be followed by adding the one line of code calling 'SetPagingFor'. For example, the 'TaskDao' might have a method that returns tasks that were completed in 2006 excluding any other tasks not done within that same year:

// TaskDao class
public IList<TaskDao> GetTasksCompletedIn2006()
{
IQuery query = Session.CreateQuery(
"some HQL statement that filters tasks by 2006...");
SetPagingFor(query); // newly added!
return query.List();
}

It is generally good practice not to pass the values for page size and number directly via the parameter list for any of these custom filtered data access methods. A few reasons to avoid this: (a) it can quickly clutter the intent of the method, and (b) it would prevent the paging functionality from being optional and, as a result, become less flexible, less reusable, and more cumbersome to work with.

Consequently, while it would be tempting to write the method's signature as such:

IList<TaskDao> list = _taskDao.GetAllTasksWithSubtasks(
param1, param2, param3, ..., paramN, pageSize, pageNumber);

It is preferable to do the following instead:

_taskDao.PageSize = 20;
_taskDao.PageNumber = 5;
IList<TaskDao> list = _taskDao.GetAllTasksWithSubtasks(
param1, param2, param3, ..., paramN);

The Downside of NHibernate Paging with ASP.NET Controls

As indicated earlier, one weakness of NHibernate's paging when combined with ASP.NET's GridView control involves some loss of "out-of-the-box" functionality. Under more conventional circumstances, when a collection of objects are bound to a GridView control, one of the built-in paging features of that control is to automatically render on the web page the navigation hyperlinks for the pages. For example, you might see following below your control:

" 1 2 3 ... 10 "

The GridView's default behavior assumes that all data bound directly to its DataSource can be paged as long as the number of items of that data is greater than its PageSize property value. Hence, if that condition is met, the control will slice up and present the data as appropriate.

Conversely, this is not true when using NHibernate style pagination. When binding to an NHibernate paged list method, the GridView's PageSize value will usually be set to the same size as the paged data list, a mere subset of the total data found in the database (or data source). Behind the scenes, the PageIndex property of the GridView will reset to zero because the number of items bound to its DataSource is less than or equal to the PageSize. Therefore, the GridView is under the impression that the data it receives is not pageable and, in turn, disables any paging features, unaware that more items do indeed exist but were just not provided at that moment. The paging features lost include not just immobilizing navigation links but also removing the availability of the event handlers linked with changing the page index.

Without the convenience of auto-generating navigation links, two options emerge that might help to produce the same desired behavior:

  1. Inherit from the GridView control and attempt to confirm whether or not if any paging methods can be overridden some how or in some way
  2. Create a custom, reusable user control to implement the navigation features

Initially, the easier path was taken by developing a very rudimentary and simple implementation of option # 2. This entailed providing in extremely basic custom controls functionality for navigating between pages using homemade "Previous" and "Next" buttons. Currently, it is not implemented as a shareable user control nor is it able to display the pages counts. I intend on exploring option # 1 a bit more in the event that option # 2 evolves into something more elaborate and unwieldy. Until then, it is a work in progress.

A third option does exist involving the possible use of the ObjectDataSource control. However, that strategy can lead down a less than desirable path for the following reasons:

  1. loss of control of how the data access is managed
  2. ease of maintainability diminishes if any widespread changes were to emerge in the future within areas of the application relying on paging
  3. disrupts and conflicts with how the MCP/MVC methodology is currently applied on the project
  4. increased difficulties in writing and running reliable automated unit tests

All things considered, despite some trade offs and a little bit of work, leveraging NHibernate's ability to do paging can be an area that could contribute significantly in optimizing and improving the performance of a data-intensive web application.

Thursday, January 15, 2009

Test Driven Blogging

Years ago when I first started learning and practicing Test Driven Development (TDD), I became extremely overzealous blindly believing all code needed to be unit tested (one of the more extreme cases were my over-the-top uses of TSQLUnit which included testing simple, low risk DDL changes that, in retrospect, was probably a bit too much with so little to gain.) This attitude was probably a common rookie mistake of becoming enamored with a new methodology (or language or framework or ....) by assuming this is how all software should be written. It is as if I had discovered the elusive magic bullet that a lot of programmers spend most of their careers searching for. Unit testing, along with its subset TDD, has steadily grown in popularity spanning the diverse programming communities spectrum. How could I possibly go wrong in my new found beliefs?

However, this past year, I have seriously reconsidered my views on unit testing. Instead, I have significantly curtailed the use of unit testing by being more selective as to when it should be applied in code. I have realized that while testing is an important tool, it is far from the "be all and end all" that others have proclaimed it to be. Instead, I readjusted my thinking to focus on what is genuinely the most important goal in programming which is to actually deliver good working software in an iterative manner.

On Stack Overflow (SO), Kent Beck an early pioneer of TDD and a creator of JUnit (the precursor for all modern xUnit style frameworks), provided a very interesting and perhaps unexpected response to the question: How deep are your unit tests?

I get paid for code that works, not for tests, so my philosophy is to test as little as possible to reach a given level of confidence.

The reality of what Beck wrote can not be ignored. (At least, I think it's him. The tone and content of his other responses on SO seem to indicate that it might just be.) Principally, working code is more important than the tests themselves. Tests can be just one of numerous methods to achieve the goal of delivering good quality software on a frequent basis but tests must certainly not overshadow this intent.

Along with Beck, it was unquestionably reassuring to read a recent post of Ayende (a notable .NET blogger/developer) that also tackles head on this very topic regarding software delivery and testing:

I want to make it explicit, and understood. What I am riling against isn't testing. I think that they are very valuable, but I think that some people are focusing on that too much. For myself, I have a single metric for creating successful software:

Ship it, often.

Keep in mind these statements are from the creator of Rhino Mocks, one of more popular mock testing frameworks for .NET. Subsequently, it carries a lot weight as it was written by someone who does truly and thoroughly understand the virtues of unit testing and TDD. Ayende is someone who I most certainly admire being as close to the ideal model of a 10x programmer in not just the realm of .NET but in programming in general (some of that admiration stems from being in complete awe of his unearthly prolific blogging). Having him confirm something that I myself have come to realize on my own this past year definitely does help to validate my current views. Quite simply, I have substantially toned down my TDD rhetoric and restrained my testing impulses in favor of renewing my true objectives in programming.

My learning TDD coincided with my learning of .NET and C#. At that point in time, I compulsively consumed the writings of a somewhat noted blogger in the .NET community who relentlessly championed unit testing and TDD. Practically treating this person's words as pure gospel, I considered this individual to be quite representative of the ALT.NET community by serving as one of the leading voices for all that it embodies. This is a community deeply immersed in the ways of unit testing and TDD.

However, with my now newly reformed outlook on software development, I have become much more wary of that blogger's "best practices" crusades. The blog still continues to be obsessively fanatical over the non-negotiable importance of unit testing and TDD almost to the exclusion of any other competing methodologies or tools. Their dogmatic writings assuredly fall into the "focusing on that [testing] too much" camp as described earlier in Ayende's post. Originally, this programmer's "test driven blog" once held one of the few selective spots on my blog's "Blog List" links. But, since it no longer carries the same relevance to me as it used to, I decided to remove it from the list.

Nevertheless, I still read that blog from time to time because it does have great information and observations regarding software development and best practices in the .NET ecosystem. In addition, I still consider myself a TDD practitioner despite reducing the scope and influence of unit testing in relation to my programming style. I just now better grok what my priorities are.

Wednesday, December 10, 2008

Disentangling Nested Transactions in TSQL

The following TSQL error (# 266) surfaced while using TSQLUnit to test a recently altered stored procedure for a legacy database:
"Transaction count after EXECUTE indicates that a COMMIT or ROLLBACK TRANSACTION statement is missing. Previous count = 1, current count = 0."
After struggling for several hours to pinpoint the problem, the debugging and troubleshooting process provided me with a better understanding of how nested transactions are managed in SQL Server. First and foremost, truly just "one" transaction can exist per connection, a fact previously not known to me. This ultimately plays a pivotal role in the above error as revealed in the the Sybase Product Manual entry on Error 266:
When a stored procedure is run, Adaptive Server maintains a count of open transactions, adding 1 to the count when a transaction begins, and subtracting 1 when a transaction commits. When you execute a stored procedure, Adaptive Server expects the transaction count to be the same before and after the stored procedure execution. Error 266 occurs when the transaction count is different after execution of a stored procedure than it was when the stored procedure began...
Furthermore:
Error 266 occurs when you are using nested procedures, and procedures at each level of nesting include begin, commit, and rollback transaction statements. If a procedure at a lower nest level opens a transaction and one of the called procedures issues a rollback transaction, Error 266 occurs when you exit the nested procedure.
The sproc under test is the "lower nest level" procedure in relation to the TSQLUnit sproc. What I discovered was that the TSQL for most of the existing stored procedures in the legacy database (such as the one being tested) contained this statement:
IF @@TRANCOUNT <> 0 ROLLBACK TRANSACTION
which was commonly found in two separate and distinct locations in the code:
  1. at very beginning of the sproc before anything interesting occurs
  2. at the very end when it's too late for it to be effective
As an example:
create proc someProc
as
begin
IF @@TRANCOUNT <> 0 ROLLBACK TRANSACTION
/* main body of the sproc */
IF @@TRANCOUNT <> 0 ROLLBACK TRANSACTION
end
This slightly odd coding convention was interfering with TSQLUnit's native stored procs' ability to perform rollbacks of all changes once an individual unit test completes execution. The aforementioned rollback statement sabotaged the outer transaction of the TSQLUnit sproc (or any other calling sproc, for that matter) by resetting the @@trancount value causing the error to be raised.

Truthfully, unless I'm missing something, that rollback code does not really provide any benefit for the original sprocs themselves. I do not fully understand the rationale for placing these lines of code in most of the database's sprocs. Perhaps it is some overcautious (and overzealous) attempt to handle any unforeseen data failures forcing cleanups at every step. However, nothing indicates this to be true or probable. Point # 2 listed above is especially puzzling since in most cases an explicit COMMIT has already taken place right before it reaches the offending bit of code. Once a commit occurs, why bother attempting a rollback?

The bug fix was simply to remove all occurrences of the rollback transaction code since it caused more harm than good. Maybe the reason for its existence was to intentionally prevent unwanted calls from other sprocs thereby keeping them isolated and independent. As with most legacy code written by others long gone, I (or any other maintenance developer that comes after me) may never know.

Sunday, November 30, 2008

Speak to me...Interpreting C#

I came across A C# REPL (in Clojure) which discusses a means by which to interact with and run C# code via an interactive command-line by using Clojure and IKVM.NET . Now, Clojure I have heard of (a Lisp implementation that runs on the JVM) but this is my first time hearing about IKVM.NET (which I now know to be a .NET implementation for JVM). The post describes how combining these two technologies gives you the potential of working with a static language like C# in a way that is quite common in the world of dynamic languages such as Python, Ruby, Boo, etc.

Having an interactive code interpreter is a huge productivity boost. It allows you to easily run and test your code as you write and modify it while not needing to pay the dreaded compilation tax which can disrupt your development flow. This dramatically tightens and shortens the feedback loop on how well your code works ranging from whether it is behaving as intended for meeting spec requirements to much more quickly identifying any runtime bugs than you would using a development process common to traditionally compiled static languages. (As an aside, these are generally the same reasons that are given for creating and maintaining automated unit tests. Same goal but different methods.)

Not sure how well this C#/Clojure/IKVM.NET approach works or how well it realistically performs (typically, interpreted languages are slower). What is certain is that this unusual implementation requires the use of the very foreign-looking Lisp parentheses. I will openly admit as someone who does not program in Lisp it strikes me as kind of strange to use and see parentheses with C# but aside from this peculiar syntactical idiosyncrasy the general concept of REPL with C# overshadows even this oddity. This quote sums up its overall appeal in the world of C#:

A REPL is a Read-Eval-Print Loop, which is a fancy way of saying "an interactive programming command line". It's like the immediate window in the Visual Studio debugger on steroids, and its absence is one of the increasing number of things that makes C# painful to use as I gain proficiency in more advanced languages.

This is precisely how I felt when I initially started to learn and use Python. Suddenly, coding in C# with Visual Studio certainly seems to now be relatively more restrictive. Similarly, whenever I have had to touch any VBA code (yes, that does happen from time to time) I customarily inhabit the VB Editor's Immediate Window (IW) pushing its limits by attempting to use it in a manner that is similar to how I code in Python.

For example, in the VB language, not only is it not required to declare the data type of a variable but it is even unnecessary to explicitly declare the variables themselves (usually this is done using the 'Dim' keyword but this can be avoided by quite simply not including the 'Option Explicit' statement). Subsequently, the first time a value is assigned to a variable, the variable will automatically and implicitly be defined on the stack just like it does in Python. As a result, you can somewhat attain that same level of interaction with code in VB (via IW) as you would in Python (via its standard interpreter) potentially gaining the productivity benefits of writing less code in contrast to strongly typed languages.

My increased reliance of the Immediate Window also extends to Visual Studio when coding in C# but it requires more work and syntax overhead versus IW in the old VB Editor. Overall, it is not quite the same experience as in Python. Regardless, as I have previously written, frequent use of the VB Editor's IW led me to lean heavily on the one in Visual Studio whenever coding in C#. Prior to that, I had somewhat forgotten it even existed. In fact, in VS 2005, the IW sometimes is missing and difficult to view when not in debug mode (this is allegedly also true for VS 2008). This is discouraging as it probably contributes to most .NET developers not favoring its use in more situations.

While I have seen other attempts at providing an interactive console for C# the following are ones I have noted to possibly try out in the very near future:
I am extremely curious if (and hopeful that) Microsoft will provide an improved implementation for VS's IW when the more dynamic C# 4.0 becomes mainstream. (How long before we have an official C#Script? It worked for VB and VBScript.)

Friday, November 14, 2008

Unit testing databases with TSQLUnit

In preparation to doing a lot of database work (think schema/DDL changes) for the next several months, I thought it would be important to define methodologies and tools to manage the development process. Having been heavily applying a test-driven development (TDD) approach in a recent project for an ASP.NET C# web application, it seemed logical and now quite natural to continue pursuing a similar path and mindset but one now more targeted towards database development.

TSQLUnit and TDD

To facilitate a smooth flow with TDD, it was key to identify a suitable testing framework to support my goal. After some research and comparisons, I eventually settled on TSQLUnit, an xUnit framework for MS SQL Server. It is interesting to note that for every programming language that exists out there, it is expected that someone will eventually create an xUnit style testing framework for it. Why should SQL Server be any different?

Database testing could be performed from the application side but the nature of the development was primarily schema/DDL changes (e.g. mostly dropping and removing tables, columns, etc.) that involved very little or no business logic. Otherwise, app code would be a better and more appropriate candidate to handle testing the db. This particular scenario lent itself to finding and using something that was as close to the database as possible ideally where the unit tests can be written and supported by the TSQL language itself. The intent was to try and follow one of the core tenets of any xUnit framework which is to do testing in the same language as the code that requires to be changed. TSQLUnit seemed the best fit.

Regardless, it is quite probable, in the future, that I might disregard all of above and still switch to testing all aspects of the database using C#. This is not because of TSQLUnit but because the TSQL language itself can be so cumbersome to work with especially if you are accustomed to the power and flexibility of a non-declarative programming language such C#. For the moment, it is satisfies my current needs for testing so it will suffice.

A Few Key Features of TSQLUnit

One feature of TSQLUnit that is critical for any type of database testing is the ability to rollback changes after each test run completes ensuring that the database is in a nice clean state before the next test starts. This simply implies that the the data will not remain altered when the next test runs potentially tainting its results. Not only does this apply to all data/DML changes (inserts, updates, deletes) but DDL changes (creates, alters, drops) as well. For example, if Test A creates a table or alters a column for an existing table then those schema changes will most certainly rollback and be undone before Test B starts to execute. Therefore, the tests themselves are isolated from each other meaning that all of the unit tests can run independently.

In addition, TSQLUnit supports the xUnit features of Setup/Teardown for a test suite. For example, if you have five tests that are logically related and are dependent on the same preconditions then you can prepare all of your data in a single, shared 'Setup' fixture and TSQLUnit will automatically run this before each associated test thereby enforcing no co-dependencies between the tests. Note that one obvious drawback with repeating the same setup multiple times might be performance if the tests rely on loading large volumes of data for the purpose of testing. As for 'Teardown', it provides essentially the same functionality as 'Setup' with the one difference of executing at the end of each test and not at the beginning.

TSQLUnit is fairly decent but I initially struggled not with the framework itself but with the usual problems with database testing such as setup of data, rollback of changes, etc. It is a lot of work because unlike in application code it is hard to stub out dependencies in the database objects such as tables, stored procedires, etc. (Especially when dealing with a 225+ column table in the good ol' legacy db I was so fortunate to be tasked to make modifications.)

Running TSQLUnit using NAnt

Once a few initial unit tests were created using TSQLUnit, the process of running them was incorporated into the project's NAnt database build script. Just like the database build itself, the unit tests makes use of the NAntContrib <sql> task for their creation and execution. These are the high level targets defined in the build script:
<!-- after building database including applying change scripts -->

<call target="InstallTSQLUnit"/>
<call target="LoadUnitTests"/>
<call target="RunUnitTests"/>

'InstallTSQLUnit' is a single sql script that runs against your target db creating all of the necessary tables, stored procedures, etc. that the TSQLUnit framework requires to function. This is simply the basis and source code for the framework itself that is integrated with the database.

'LoadUnitTests' runs the sql scripts that contains the tests themselves located in a 'Tests' folder in the project's directory. To elaborate, it creates all of the unit test sprocs along with, if necessary, injecting any test data into the database that is not handled by the Setup fixtures.

Finally, 'RunUnitTests' calls the TSQLUnit command to run all of the unit tests inside the database:
<target name="RunUnitTests" description="Run all unit tests "
if="${installUnitTesting}">
<sql connstring="${connectionString}" transaction="true" delimiter=";" delimstyle="Line">
exec tsu_runTests;
</sql>
</target>
The NAnt db build is configurable so that you can specify whether or not to include or exclude the unit tests. This might be necessary if you just simply want to only build the database and nothing more perhaps for the sake of reducing the amount of the build time if the intent is to use database for another purpose other than testing.

In the command-line window, as NAnt logs the progress of the database build, at the end it will bubble up the output results of TSQLUnit indicating whether the tests passed or failed:
...
ExecuteSql:

[echo] loading .\Database\Tests\ut_DeleteTables_VerifyTablesDropped.sql

RunUnitTests:

[sql] ====================================================================
============
[sql] --------------------------------------------------------------------
------------
[sql]      SUCCESS!
[sql]
[sql]      14 tests, of which 0 failed and 0 had an error.
[sql]  Summary:
[sql]  Run tests ends:Feb 20 2008 11:44AM
[sql] --------------------------------------------------------------------
------------
[sql] Testsuite:  (14 tests ) execution time: 76 ms.
[sql] ====================================================================
============
[sql]  Run tests starts:Feb 20 2008 11:44AM
[sql] ====================================================================
============

BUILD SUCCEEDED

Total time: 6.1 seconds.
Currently, the overall database build does not fail if the unit tests themselves fail since NAnt can not catch and interpret TSQLUnit results. This codeproject MS SQL Server script validation with NAnt Task seems to provide that level integration between NAnt and SQL Server unit testing. Perhaps, this functionality might be implemented later, but, for now, it is good enough.

Other related posts on TSQLUnit:

It's True (And Not False): Assert Equality in TSQLUnit

Database schema changes unit tested using TSQLUnit

Sunday, November 9, 2008

Relax and "unwind" with recursion

I was recently looking to change some values in test data that was scripted in TSQL insert statements that I was not too fond of. This data is loaded on development and test builds of a database for a system that I work on.

The data changes center around some arbitrary ID numbers. These values are not system generated but can be considered to be natural primary keys since they are defined externally outside the system and they are used and referenced by the end-users signifying meaning in the business domain. However, for development and testing purposes, the values can be anything.

At first, the numbers reflected actual numbers that preexisted outside the testing and dev environments but I found them too difficult to remember when testing the application manually or when defining automated unit test case scenarios. Therefore, I decided on replacing the existing ID numbers with a sequence of numbers that I can recall more easily:
1234567890, 2345678901, 3456789012, ..., 0123456789
I figured this list of numbers would be easier to remember on the fly rather than if they were randomly generated. You can see an obvious pattern here hence lending themselves well to be committed to (human) memory. The initial number in the list is a universally simple value of 1234567890. Each subsequent number is the same except that the first digit is moved from the first position to the last position as compared to the preceding value in the list. For example, the number '1' in 1234567890 gets relocated to the end to become 2345678901.

I decided to write a simple Python script to update all of the data sql files with these new numbers. Now, I could have quite obviously created the list manually in a very short time in my script such as:
new_id_numbers = [1234567890, 2345678901, 3456789012, ..., 0123456789]
However, I always like to find opportunities to challenge my programming abilities even in some inconsequential situations such as this one. The challenge I created for myself was to see how I can programmatically generate this exact same list. Evidently, a pattern exists with these numbers implying code can be written to produce this particular set of values without the need to manually type them out.

My first impulse was that I could write some kind of iterative loop to generate the list:
# iteration version
def get_swapped_numbers(numbers):
first = numbers[0]
for item in numbers:
if len(numbers) == len(first) or len(first) == 0:
return numbers
last = numbers[-1]
new = last[1:] + last[:1]
numbers.append(new)
return numbers

>> initial_value_list = ['22566']
>> print get_swapped_numbers(initial_value_list)
['22566', '25662', '56622', '66225', '62256']
It works. Nothing unusual here. However, I recognized that this particular numerical pattern is indeed recursive in that each value in the list is dependent on the previous value and that recursion could be used to solve this as well. Like probably most programmers, I have never used recursion in actual code but it has been one of those fundamental concepts in computer science that I felt that I needed to better understand and explore. As a result, this simple pattern provided an excellent opportunity to flex my recursive muscles.

After mulling over for some time on how to implement a recursive function for this specific problem here is what I eventually churned out:
# recursion version
def get_swapped_numbers(numbers):
first = numbers[0]
if len(numbers) == len(first) or len(first) == 0:
return numbers
last = numbers[-1]
new = last[1:] + last[:1]
numbers.append(new)
return get_swapped_numbers(numbers) # recursion!!

>> initial_value_list = ['22566']
>> print get_swapped_numbers(initial_value_list)
['22566', '25662', '56622', '66225', '62256']
To build your recursive function, the most important piece is that somewhere in the body of the function the function must call itself by name:
    return get_swapped_numbers(numbers) # recursion!!
Without it, well...you just have a plain ol' vanilla function.

The other very important piece of a recursive function is to include some kind of a conditional statement that acts like a guard clause which is commonly referred to as the 'base case' in recursion lingo. This base case will cause your recursive calls to stop and begin to "unwind" itself as it spirals back up to the first initial call. If a base case is not included then you run the risk of unleashing an ugly infinite loop.

The base case is really no different than the break/return point in the iteration example:
    if len(numbers) == len(first) or len(first) == 0:
return numbers
In fact, any recursive function can be written and expressed as an iterative loop. This is probably why most programmers do not use recursion since you can achieve the same results using more familiar, day-to-day techniques. In addition, traditionally in most languages, recursion tends to perform slower than their loop counterpart.

So, why even use recursion when iteration can suffice? The real benefit is that sometimes a recursive function can end up being more readable and clearer in intent than an iterative function (although in my example it is a wash in this aspect). It also seems that certain types of recursion (e.g. tail recursion) are optimized by compilers so it could truly provide better performance with the added bonus of improved readability.

Truthfully, writing the loop was a lot easier than the recursion version. I am uncertain that the reason is because writing loops are so ingrained and second nature to me having created so many over the years in code coupled with the fact that this was my real first attempt to implement a true recursive function. Admittedly, it was a bit trippy mentally working through each function call to ensure avoiding the dreaded infinite loop. However, the same could be said when I first learned writing loops many years ago. With more time and practice, I can probably create recursive function without exerting any more thought than I would with creating a loop. All in all, even if I never again use recursion in my code, it is still an important technique for programmers to understand and recognize especially if encountered in code you did not write.