Jim's Blog Ramblings about novels, comics, programming, and other geek topics

29Nov/072

Simple Introduction to Unit Testing

Google AdSense

For some unknown reason, I fell in love with Unit Testing after first reading about it a few years ago. I think it's the concept of trying to break another developer's code, trying to out think another developer, and trying to find holes in their implementation that intrigues me. I haven't written as many Unit Tests as most developers, so maybe that's why I still like writing these tests.

I believe that it's not a good idea to have the programmer write their own unit tests, because most of the time if the programmer could think of various ways to break their code, they would have implemented solutions for it. It's much better for another developer to write Unit Test cases for the code, since they may not have intimate knowledge of the actual implementation details.

Although, sometimes you don't work on a team of programmers or have other programmers available to write Unit Tests for your code. In most of my recent projects, I was/am the only developer so I need to write my own Unit Tests. I've found that for the most part, the Unit Tests aren't very useful because I've accounted for everything that I can think to test in the implementation. But every now and then, I've found a few methods where testing with nulls or boundary conditions returns an error that I need to resolve.

What is Unit Testing?

Simply put, Unit Testing is when you write code that tests individual units (methods/classes) of a program. So if you write code to test a class method, then that's a Unit Test. Unit Testing does not eliminate other forms of testing. It compliments testing by testing staff and alpha/beta/end-users.

Why use Unit Testing?

Unit testing allows developers to test their own code before Testing staff gets a chance to test it. I also think that most of the time, Unit Tests will test parts of the code that normal testers won't or can't test. In my experience, most of my testers are usually testing items they can access via the user interface. If there's anything going on in the background, then they can't really test it unless something in the UI breaks and then you would need to start at the UI and debug backwards until you find the actual method causing the problem.

Example of Unit Testing:

Here's the signature of method that we will write some test cases for.

public static string ArrayToCommaDelimitedList(string[] valueArray)

This method takes an array of string values and returns a comma delimited list of items. For example, if we passed in two strings of "A" and "B", then we should get "A, B".

The first test we'll create will be to just validate the example we just mentioned. When naming Test classes, I use a standard such as:

  • Namespace naming: ProjectName.Tests.Helpers, where classes to be tested will be in ProjectName.Helpers. I just insert "Tests" as a namespace and try to use the same Namespace names to make organizing my tests easier to find. The above method that we are testing will be in ProjectName.Helpers namespace and the Tests will be in ProjectName.Tests.Helpers. I also create a second Visual Studio project to hold the test cases and never include the test cases in the same library as the code to be tested. 
  • Class naming: ProjectName.Tests.Helpers.ArrayHelperTests. I append "Tests" to the end of the class name. I like to have one Test class per implemented class. The only difference is that "Tests" is appended to the end of the testing class name and the test class includes a namespace of "Tests".

Here's the code for MyProject.Tests.Helpers.ArrayHelperTests class. In this example, I'll be using MbUnit's Unit Testing Framework.

using System;
using MyProject.Helpers;
using MbUnit.Framework;

namespace MyProject.Tests.Helpers
{
   [TestFixture]
   public class ArrayHelperTests
    {
       [Row(new string[] { "A", "B", "C" }, "A, B, C")]
       [Row(new string[] { }, "")]
       [Row(new string[] { null }, "")]
       [RowTest]
       public void ArrayToCommaDelimitedList(string[] listItems, string expectedOutput)
       {
           string actualOutput = ArrayHelper.ArrayToCommaDelimitedList(listItems);
           StringAssert.AreEqualIgnoreCase(expectedOutput, actualOutput);
       }
   }
}

The above test class has one test case (RowTest) with three sets of testing criteria (Row). This is one of the better functions of MbUnit. Some Unit Testing software doesn't allow you to use RowTests, so you would need to create a different Test Method for each set of criteria (if you're Unit Testing framework doesn't support a RowTest like feature, then you would need to create three test case methods for the above example).

Using TestDriven.NET Visual Studio add-on, I can just right click the project, namespace, class, or method to start the Unit Testing. After MbUnit is finished testing, it makes a nice Test Summary HTML report document that includes details of each Test with pass/fail and exception messages.  The output of the testing was:

2 passed, 1 failed, 0 skipped, took 2.23 seconds

Now, let's examine why we had a failed test. The testing results provides us details on why the test failed stating:

[failure] ArrayHelperTests.ArrayToCommaDelimitedList(System.String[],)
TestCase 'ArrayHelperTests.ArrayToCommaDelimitedList(System.String[],)'
     failed:  Equal assertion failed: [[]]!=[[, ]]

It appears that Test #3 failed because the method we are testing does not correctly render a list with a null value. Our expected output was "" and the actual output was ", ". Since the actual output is not what we expected or want, we can now go back and fix the method to properly handle a null value and then re-run the tests to validate the changes. After making the change by adding a IsNullOrEmpty check on the values passed to the method and rebuilding the projects, all three test cases now pass.

Unit Testing Frameworks and Tools

Frameworks:

Tools:

 

27Nov/070

Are you in the 80% or the 20% of programmers?

Google AdSense

Jeff Atwood of Coding Horror writes an interesting article worth mentioning and reading by any programmers out there. He points out that there's only two types of programmers.

Jeff's article is based on Ben Collins-Sussman's article written about a week earlier. Ben writes:

The 20% folks are what many would call “alpha” programmers — the leaders, trailblazers, trendsetters, the kind of folks that places like Google and Fog Creek software are obsessed with hiring. The 80% folks make up the bulk of the software development industry. They’re not stupid; they’re merely vocational.

Jeff points out (not in so many words) that a lot of programming bloggers happen to be "alpha" programmers (or would like to be considered as much). These bloggers often forget about the 80% of the industry and take on an elitist approach to programming. I've seen this happen many times in blogger's attitude and content. Hopefully Jeff's call to programmers might have some impact.

I've always wanted to be in the 20%, but I know that I'm sitting over in the 80% boat. I'd like to think that I might know enough to be on the edge there straddling between the two groups, but I just don't use enough of the trending techniques, patterns, technologies, etc. to stay up to date on everything. Nor do I want to spend my weekends reading new software engineering, design patterns, etc.

If you're in the 20%, just don't forget about the majority of programmers out there. Most of us are still reading your blogs and experimenting with new technology, but some of us just don't have the time to keep up with everything going on or the flexibility to try as many different things at work as we'd like.

Jeff sums this up with a call to alpha programmers/bloggers stating:

If you really want to change the software development status quo, if you want to make a difference this year, you have to help us reach outside our insular little group of alpha programmers and effect change in the other 80% of the world.

My Related Posts: ,

27Nov/070

I’m glad it has a name…

This morning's Dilbert cartoon had me rolling.  The pointy-hair boss commands Dilbert's team to start using Agile programming.  In the boss's description, he states that Agile programming means "no more planning and no more documentation." The boss goes on saying that the programmers can "start writing code and complaining."

View Dilbert Cartoon

My Related Posts: , ,
21Nov/071

Free HD content

After recently purchasing my HDTV, I found that my cable provider sends the local channels (ABC, NBC, CBS, PBS, CW/WB) over the cable for free. If I had a antenna set up, then I could get HD free from the signal feed, but it's nice to get  something for free. These HD feeds are called "over-the-air broadcast" since the channel is providing the broadcast via their antennas and the cable companies are just relaying that signal to coaxial.

If you have a digital TV, then you can just enter the following channels for the San Diego area. You can click here to find HD channels in your neighborhood.

One of the great things about the XBOX 360 is that you can stream HD videos from your computer to your HDTV via the console (without having a HD DVD player). You can also stream music and browse your photographs from your "My Photographs" and "My Music" folder via Windows Media Player.

One downfall that I noticed is that the videos need to be in WMV format, but luckily the music can be in MP3 format. So you can stream your own music as you are playing your favorite games.

After looking around the Internet for some free HD movies to test the PC-to-XBOX wireless streaming, I found Microsoft's WMV HD Content Showcase. There's a few good downloads there, but mostly 1-3 minutes. The downloads are a great way to test your PC-to-XBOX connection with HD movies. The downloads vary in size between 20 MB and 240 MB. Most videos are provided in both 720p and 1080p formats.

I also found "world's first High Definition TV series distributed directly on the Internet" (and free too). The web site mariposaHD.tv provides 25-35 minutes HD TV shows on three primary subjects: adventure (sports, hiking, surfing, biking, etc.), beauty (lots of South American women in bikinis), and style (mostly clothing and some more of bikini models, etc.). The shows are downloaded via BitTorrent which is nice since the files are around 1.4-1.8 GB each. All shows are offered in both 720p and 1080i formats. One of the recent shows (episode 6) has about 10 minutes of a tiësto concert in HD.

Also, you can download individual movies or TV shows via XBOX Live Marketplace directly to your XBOX's hard drive. The Marketplace works a lot like iTunes in that each TV episode and movie is around $2-$6. There's also free movie trailers, game demos, game trailers, etc. that you can download for free using just your XBOX console.

And finally, you can make your own WMV HD movies that can be viewed via your XBOX (without HD DVD) by just writing the WMV files to a CD-ROM. If you want to author your own WMV HD files, then you should read the WMV HD authoring guide.

My Related Posts: ,
19Nov/072

Debugging assembly loading within a unit test project

I reorganized one of my projects and discovered that my MbUnit tests no longer worked. The error stated that one of the assemblies could not be loaded, but it worked fine before I removed and added the project to another solution. The assembly in question was the SubSonic assembly.

This took me a little while to work through and I wasn't able to find any helpful blogs or documentation to help. So I figured that I'll contribute to the blogosphere and maybe someone else might find this useful.

I thought through the problem and finally figured it out. I had forgotten about how MbUnit executes. Even though, MbUnit's output is sent to the Visual Studio's output window, the tool runs in a separate process - remembering that I was able to debug and figure out how to solve my problem.

The root cause was that the assembly wasn't in the working directory for the test assembly so it couldn't be loaded by MbUnit. The SubSonic assembly was not in the GAC, the SubSonic directory wasn't in my %PATH%, and the assembly's "Copy Local"property was set to false.

By changing the "Copy Local" property, the test project automatically copied the SubSonic assembly to the bin directory and MbUnit was then able to load the assembly without any errors. Alternatively, you could add SubSonic to your GAC (Global Assembly Cache) or add the SubSonic directory (the directory with the .dll file) your environment path. Here's a little more information and the steps I used to resolve the problem.

Software

  • Visual Studio Professional 2005
  • SubSonic 2.0.3
  • MbUnit 1.0.2700 Add-in
  • TestDriven 2.8 Add-in

Symptoms

TestCase failed: An error occurred creating the configuration section handler for SubSonicService: Could not load file or assembly 'SubSonic' or one of its dependencies. The system cannot find the file specified.

System.Configuration.ConfigurationErrorsException

Message: An error occurred creating the configuration section handler for SubSonicService: Could not load file or assembly 'SubSonic' or one of its dependencies. The system cannot find the file specified.

Source: System.Configuration

StackTrace:
    at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)
    at System.Configuration.BaseConfigurationRecord.GetSectionRecursive(String configKey, Boolean getLkg, Boolean checkPermission, Boolean getRuntimeObject, Boolean requestIsHere, Object& result, Object& resultRuntimeObject)
    at System.Configuration.BaseConfigurationRecord.GetSection(String configKey, Boolean getLkg, Boolean checkPermission)
    at System.Configuration.BaseConfigurationRecord.GetSection(String configKey)
    at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection(String sectionName)
    at System.Configuration.ConfigurationManager.GetSection(String sectionName)
    at SubSonic.DataService.LoadProviders()
    at SubSonic.DataService.GetInstance(String providerName)

Inner Exception:
    System.IO.FileNotFoundException
    Message: Could not load file or assembly 'SubSonic' or one of its dependencies. The system cannot find the file specified.

Source: System.Configuration

StackTrace:
    at System.Configuration.TypeUtil.GetTypeWithReflectionPermission(IInternalConfigHost host, String typeString, Boolean throwOnError)
    at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.Init(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord)
    at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory.InitWithRestrictedPermissions(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord)
    at System.Configuration.RuntimeConfigurationRecord.RuntimeConfigurationFactory..ctor(RuntimeConfigurationRecord configRecord, FactoryRecord factoryRecord)
    at System.Configuration.RuntimeConfigurationRecord.CreateSectionFactory(FactoryRecord factoryRecord)
    at System.Configuration.BaseConfigurationRecord.FindAndEnsureFactoryRecord(String configKey, Boolean& isRootDeclaredHere)

Solution

  1. Expand "References" of the Test project
  2. Select "Subsonic" library
  3. Set "Copy Local" to true
  4. Rebuild the test project
18Nov/073

Beowulf: IMAX 3D Experience (Movie Review)

Best movie evar...

IMAX 3D...

I wasn't too familiar with the Beowulf story, but I knew a little about it before seeing this movie. I had wanted to see the movie based on the previews, but I had never seen a IMAX 3D movie before. Sure, I'd seen a few IMAX movies and a few 3D movies, but never the two combined.

This movie was incredible in IMAX 3D. Unfortunately, I just happen to see it on the first day of showing and after one of my worst Starbucks experiences ever (imagine waiting in line for 30 minutes for a basic cup of coffee and then finding out that they were out of coffee), ended up getting there late and getting a second row seat that was too close to the screen to be fully enjoyed.

In the San Diego area, I believe that the Edwards Mira Mesa Stadium 18 theater is the only IMAX theater in the county, but you can check here for local IMAX showing.

The entire movie was full 3D and look near perfect. There were a couple  distortions in the 3D effects, but that might have been due our seats. Overall, I'd probably like to revisit and watch this again in the IMAX 3D showing after a few weeks have passed and the crowds were less and allowed a better and easier seating.

IMDB scores this a 7.0/10, but I really disagree with this. If the reviewers experienced the same movie in the same setting, then I think it could easily get 1 or 1.5 more stars from the IMAX 3D experience. The cast includes John Malkovich, Anthony Hopkins, and Angelina Jolie.

My Related Posts: ,

14Nov/070

ASP.NET AJAX Rich Text Editor

I've been looking for a nice ASP.NET AJAX text editor control for a little while now. There's quite a few JavaScript based controls and AJAX controls using other AJAX libraries, but I've been trying to keep my projects to a single AJAX library.

The author, Kannan Sundararajan, posted the source code over at CodePlex. His friend Kirti has also written up a nice article discussion some of the control's features.

My Related Posts: , ,

7Nov/070

Spider-Man 3: The battle within (Movie Review)

As you may have noticed with my last movie review, I'm a bit behind on watching movies. I'm just now getting around to watching Spider-Man 3 on DVD.

Growing up, Spider-Man was never one of my favorite superheroes. I always thought that Peter Parker was too whiny in the comics and so far I think they've done a good job bringing that to the movies.

Okay, back to Spidey... In fact, his arch-nemesis Venom was one of my favorite comic book characters - and my favorite super-villain. So I went into this moving hoping that they don't spoil my childhood memories of Venom and hoping they elude to Venom's offspring, Carnage for a future movie (if more Spider-Man movies come after this one).

I wasn't very entertained with the previous Spider-Man movies, but they weren't too bad as far as comic book movies goes. In this sequel, the alien symbiote arrives from outer space and finds Spider-Man. This alien (as all Venom fans already know) bonds with Spider-Man to become the black Spidey-suit. This alien enhances his abilities, but also begins to try to take over his conscience as well. Eventually, Spidey frees himself from the alien and it bonds with another person.

The movie description on the Netflix jacket talks about Sandman, but doesn't even mention Venom. From IMDB Trivia, nobody in the movie even calls Venom by his name.

The drama between Peter Parker, Harry Osborn, and Mary Jane reminds me a lot of Smallville for some reason. Giving Sandman a background like this (trying to get money to save his daughter due to a medical condition) was a nice touch, but why are people doing experiments in the middle of the marshlands?

As a bonus, Bruce Campbell has a cameo roll as the French Maître d’. Also, the few scenes with Doctor Connor was a nice touch. Hopefully, they'll continue making the Spider-Man movies long enough for him to become Lizardman.

Exactly, how many extra masks does Spidey carry with him? Seems like its been ripped off or lost a few times and he keeps finding it or getting a new one.

The movie scores a 6.8/10 from IMDB, which is even lower than I would have thought.

My Related Posts: ,
6Nov/071

Saving and truncating values to fit with SubSonic

For one of my applications that I'm working on, I have two different data sources where one needs to push data to the other. However, since both data sources were not designed for this, there's a few destination fields that are shorter than the source fields.

To resolve this, I needed to truncate any values to fit within the maximum size of the destination fields. If there were only a handful, then it would be easy enough to code. However, there's several dozen fields and just to make sure I don't miss a field, I wrote the below code to loop through the destination fields and automatically truncate any values that exceed the maximum length.

After asking if there was a SubSonic way to do this, I learned that there wasn't any code already written. Montyguy recommended that I override the BeforeValidate method of my Data Access Layer (DAL) related class instead of calling a separate function in my code.

protected override void BeforeValidate()
{   
   //Truncates any string columns
   //to the maximum length of the field
   foreach (TableSchema.TableColumn col in 
            this.GetSchema().Columns)
   {
      if (col.DataType == DbType.String &&
          !string.IsNullOrEmpty(
            this.GetColumnValue<string>(col.ColumnName)) &&
          this.GetColumnValue<string>(col.ColumnName).Length > 
             col.MaxLength)
      {
         string newValue = 
            this.GetColumnValue<string>(col.ColumnName).
               Substring(0, col.MaxLength);
         this.SetColumnValue(col.ColumnName, newValue);
      }
   }
   base.BeforeValidate();
}

The above code loops through each column/field in the table/class and checks to see if the value is not null or empty and if the length exceeds the maximum length defined by the database. If so, then it takes a Substring of the value and sets the column to the truncated version of the original value.

My Related Posts: , , ,
6Nov/070

Day of Jury Duty

I've walked past the Hall of Justice for a while and always wanted to enter it. I thought that I'd find Superman or one of his super friends from the legion there, but it was just ordinary people that was a little disappointing.

7:30 Wait in line for metal detectors

7:35 Elderly lady's knitting needles confiscated at metal detectors

7:45 Jury duty introduction and overview movie

8:45 Half-hour break

9:15 Forgot to write down exactly how many days my company will pay for, called into Jury Services office to fill it out, called work to find out

9:40 Still no answer from work, admin thinks its either one or two weeks

9:50 Worked called said company pays for all time spent at jury duty. Oh great...

10:10 Name called.. Uh oh.. Going to a department court room. Got to walk across the bridge to the county courthouse.

10:30 Department roll call

10:45 Entered the court room and listened to judge's lecture. The judge begins asking questions to help the attorneys select the jury pool. It is a felony trial. Luckily, I wasn't one of the first twelve called. Judge begins asking questions for the first set of twelve. The trial expected to take 4-7 days. Noticed that the first twelve was weighted towards men (9 men, 3 women) while the entire jury pool sitting in the audience is a majority of women.

12:00 - 1:25 Lunch break

1:25 Judge finishes asking questions to first twelve.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

3:00 Started noticing a pattern with the dismissed jurors. About 30 people left in the room that can be called. I'm starting to get a little nervous.

Juror dismissed. Another called.

Juror dismissed. Another called.

Juror dismissed. Another called.

3:45 Guy sitting next to me mentions that he notices the pattern also.

Juror dismissed. Another called.

4:15 Both prosecution and defense rests with jury selection.

4:20 Alternate juror called. Dismissed.

4:25 Second alternate juror called.

4:30 Final jury consists of 9 (+1 alternate)women and 3 men (complete inverse of original panel). Everyone dismissed.