Wednesday, April 08, 2009
OK people. STOP putting cowboy code on my desk. Seriously. TEST your software. REALLY. Please STOP writing BRAND NEW LEGACY code.
< /Rant >

OK I feel better. But not really. Just because a system is not considered to be a "production release" (meaning that people outside the particular organization or business won't have access to it) it DOES NOT mean that we can cowboy it up and plop a steaming pile of untested code out there for our colleagues or coworkers to consume.

ALL CODE NEEDS TESTS. Period.

Untested code is NOT finished. Please don't just assume that if the code "works" that it's ready to inflict on other people (or even yourself). Self-inflicted legacy code casualties are the second highest cause of career paralysis, according to 4 out of 5 dentists. By definition, code is "legacy" if it doesn't have tests.

Here's a plan to get your tests caught up.

Start Small
At least we need a set of "sanity" checks... if nothing else. Create a "test suite." Use xUnit or the like, keep it simple. Start with the checks for the obvious output... if that doesn't show up, then something is clearly broken.

Add Some More
One at a time if you have to, add another test for something. Any kind of test will do... unit, functional, acceptance... I recommend starting with acceptance and working backward. We already blew the op to be able to do TDD and get unit testing done, so now let's just make sure the surface behavior is adequate. Definitely do go in deeper if time permits.

New Feature
Each time a new feature is added, update the test suite to make sure everything is happy with changes that ripple out from the effect of the feature. Again - at least make sure that the obvious functionality is tested on the new code. Don't slack on it, keep at least the new code from being legacy.

Lather, Rinse, Repeat
Pick a time each week (say 4:30PM on Wednesdays) to put in a half-hour on writing one new test. Schedule it. Block the time out on your calendar so someone can't schedule a meeting... And hide if you have to - to avoid distractions.

What to Write
Focus on happy-path code tests only if there are none for that feature. Otherwise, do alternate and failure path tests, so that the behavior of the system is understood in circumstances other than the best-case. 90% of bugs occur in the not-happy path.

Using this strategy will get testing started, and contribute to a more robust and reliable product, no matter what it is. Remember that most "side projects" or "utilities" that are developed in-house will be used by your own people. We want them to have the best.

"But it's just a spreadsheet." OK, yes it is. I say we need to make sure to test even the lowly spreadsheet. Because, next week someone in Finance is going to discover it and begin to use it for their payroll planning... if there is a critical flaw in it, it might be YOUR paycheck that gets eliminated!

We should realize that even internal tools and web sites are usually used to make business decisions of some kind. We want to make sure that they are made using reliable tools, to the extent possible. Business relies on its data, now more than ever. Competition is fierce in a down economy - even small mistakes can be a big problem.

"Bread's not done until it's baked" - and neither is code! SO PLEASE: Test it. Bake it. Slice it... and don't get burned!

Wednesday, April 08, 2009 11:05:23 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]  | 
Saturday, November 15, 2008
Here is a presentation I wrote on what Unit Testing is all about, and how TDD fits into the ATDD cycle.

There are specific things here on testing the UI code with Selenium and JSUnit, and recommendations on how to do unit testing on your database code.

This presentation is in PDF format, but I can post the PPTX format also if needed.

A Practical Guide to Unit Testing1.pdf (503.29 KB)

ATDD | Mocks | Refactoring | Selenium | TDD | Testing | Unit Tests | SQL
Saturday, November 15, 2008 1:08:59 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]  | 
Tuesday, October 07, 2008
Do you ever wonder why there is an extra "False" printed at the end of each run for unit tests?

C:\Code\sample>ipy UnitTests.py
.....
----------------------------------------------------------------------
Ran 5 tests in 0.395s

OK
False


It looks like there is an exit statement buried inside the unit test framework. We can eliminate the problem pretty easily with the addition of a try/except around the unit test execution. Here is the code to put at the end of your unit test script:

if __name__ == '__main__':
    try:
        unittest.main()
    except SystemExit:
        pass

This catches and eats the SystemExit exception, and runs without printing the "False" at the end of the execution:

C:\Code\sample>ipy UnitTests.py
.....
----------------------------------------------------------------------
Ran 5 tests in 0.387s

OK

cheers!

Tuesday, October 07, 2008 8:09:49 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]  | 
Monday, January 14, 2008
Have you ever wanted to test a table in the database for the correct structure? Ever had someone make a column nullable that shouldn't have been? ever have someone make a column VARCHAR instead of NVARCHAR? INT instead of BIGINT? SMALLDATETIME instead of DATETIME? This is an easy way for bugs to creep in - when the code is written for one version of the database and then someone makes a change... So if you haven't been testing your tables (SQL should be TDD'd too), perhaps you should...
 
Here is a handy stored procedure you could use that describes a table in an easy-to-test way.
 
CREATE PROCEDURE describe (@table_name varchar(90))
AS
SELECT DISTINCT
  sc.column_id as ColumnNumber,
  cols.column_name as Name,
  cols.data_type as Type,
  ISNULL(cols.character_maximum_length, 0) as Length,
  cols.is_nullable as Nullable
FROM

  information_schema.columns cols

  INNER JOIN sys.columns sc ON

    cols.column_name = sc.name

    AND OBJECT_NAME(sc.object_id) = @table_name

ORDER BY sc.column_id
 
Just call it with the table name and it produces a nice format the tests can use to extract the info they need to check.
 
# Name         Type     Length Nullable
1 Id           int      0      NO
2 TypeId       int      0      NO
3 Name         nvarchar 50     NO
4 Description  nvarchar 1500   NO
5 CreateDate   datetime 0      NO
6 UpdateDate   datetime 0     YES

just employ a data reader to read the data in the test, and your unit tests can ensure that all of the tables have the right structure.
SQL | Tools | Unit Tests
Monday, January 14, 2008 8:15:53 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]  | 
© Copyright 2010, John E. Boal