Wednesday, November 25, 2009

Generics your easy road to the simple life

There have been some comments recently asking what was the best way to use Generics in C#, so here’s a short blog which sheds some light.  Generics were probably the most powerful feature to go into .Net and they allowed developers to define structures, without committing to actual data types.  That may sound very complicated but its really not that hard to wrap your head around.

Simple Generic Lists

One of the simplest examples is taken directly from an existing Framework.  Within this we have lots of Collections classes for example CompanyCollection, ContactCollection, etc. and these are explicitly created with lots of code for getting a group, array of Company or Contact items from the CompanySearch class. 

It's usually seen in this type of context:

// Get a collection of companies

CompanyCollection compCollection = CompanySearch.Browes();

string companyName = compCollection[0].CompName;  // display the first company name

Generics give you the same thing out of the box using the List<> function.

// Get a collection of companies using Generics

List<Company> compCollection = CompanySearch.Browes();

string companyName = compCollection[0].CompName;

So what's the advantage?  Well for one we don't need the CompanyCollection.cs class file which will save a developer having to write it (cut/paste or use replicator and perhaps introduce bugs).  Secondly it's been developed using core functions so it's faster than anything you could write yourself.  Also it's guaranteed to give us a stable upgrade path as .Net progresses.

The Syntax

Taking this example a little further, I hear “What’s all this <> crap in the code?”.  Well simply, this is the class you are passing into a “generic” (i.e. self defined) method.  An easy way to describe this is to think of it as a cut/paste job for the class.  Below is an extract of the CompanyCollection class with a Browse method.

using System;
using System.Collections;

namespace BusinessObjects.Companies
{
    public class CompanyCollection : CollectionBase
    {
        public CompanyColelction Browse()
        {
              CompanyCollection results = new CompanyCollection();
              … some code to find a bunch of records and put them in results …
              return results;
        }
}

If you wanted the same thing for Contacts you would probably cut/paste the code into a new file and replace every occurrence of “"CompanyCollection” with “ContactCollection”.  With Generics you would say something like this.

using System;
using System.Collections;

namespace BusinessObjects.Companies
{
    public class GenericList<T>
    {
        public GenericList<T> Browse()
        {
              GenericList<T> results = new GenericList<T>();
              … some code to find a bunch of records and put them in results …
              return results;
        }
}

Here at compile time the .Net Framework will replace the “T” above with the object value you are passing to the method.

GenericList<Company> myCompanyCollection = new GenericList<Company>();  // replace “T”
myCompanyCollection.Browse();

and

GenericList<Contact> myContactCollection = new GenericList<Contact>(); // replace “T”
myContactCollection.Browse();

Hence in the compiled DLL, you do actually get two classes “generic classes” but you only have to write (or edit, debug, etc.) one!

Thursday, November 19, 2009

Some coding tips and advice

I've been doing some refactoring code recently and want to share some tips and tricks that could help developers in future efforts.  These are just suggestions so feel free to use or ignore any of them, but keep in mind that they would make things a little easier for everyone in the long run.

Temp Files and Paths

I've seen in a few places that developers have been placing files into the C:\temp directory.  Nothing wrong with this; however did you know that .NET makes it a lot easier now?

Before:    string fullFileName = @"c:\temp\" + someFileName;
The main problem here this is that it assumes that the "c:\temp\" directory exists and if you want to change it we have to recompile the source code.

After:      string fullFileName = String.Format("{0}{1}", Path.GetTempPath(),
                                                                                 Path.GetTempFileName());
The "Path" class in .NET will gives you lots of extra options for dealing with folders and files.  The "GetTempPath" method will return the value set in the %Temp% environment variable which is default in Windows.  "GetTempFileName" will give you a random filename which can be very handy if you are creating temp files.  Another handy methods are "GetFileNameWithoutExtension" which means you can add any extension you want to a file.

Getting rid of old code

You all know how much I *hate* to leave old code hanging around, but leaving an entire classes really gets me going!  The current Framework is chock full of classes that are old, duplicated or simply in need of a serious rewrite, but we can't delete them as there is the ever present "Possibility" of breaking the old ASP code.  To address this we can use the "Obsolete" attribute to show a class should no longer be used.

    [Obsolete("This class is a deprecated! use Company from DataAccessObjects Namespace.")]
    public class Company
    {     ......     }

We can also say something like this  [Obsolete("This class is a deprecated and will throw a compile error!", true)].  This is Visual Studio will generate a compile error, but it's probably not something you'd want to do unless you really wanted to spend a long time testing.

Never..Never.. Never.. Swallow Errors!

I've seen this type of code all over every project and it's really bad practice.

     try { someCode;
           someMoreCode; }
     catch (Exception e) { }
AAGHHH!!! having a catch with nothing in it is like driving drunk with your eyes closed and having no insurance, it's just saying "If I crash, just keep going and leave all that damage for someone else".

     try { someCode;
           someMoreCode; }
     catch (Exception e) { throw new e;}
This is a little (but not much) better than the last example; least this this we acknowledge that a problem took place.  The problem with this approach is that as we're throwing a "new e" so we actually loose the strack trace and if the error is deep in the bowls of the code you'll have a hard job finding the cause.

     try { someCode;
           someMoreCode; }
     catch (Exception e) { throw;}

This will give you both the error and the stack trace, but really at this point its probably easier to just say:

         someCode;
         someMoreCode;

So what's the moral of our story?  NEVER have a try-catch block unless you actually need to do something with it, log the error, throw a different error, it’s up to you but please do something in the catch block.

Creating Projects in the right folder

A very minor thing on the list is to keep an eye on the directory when you're adding a new project to an existing solution.  By default if I was to add a new project to a solution it will go under the root folder.  There however a text box on the New Project dialogue which gives you the option to add a subdirectory name.

Friday, November 13, 2009

PSTools .. it’s great to find a good tool for once!

I was looking for a way to run scripts on a remote server and found this great set of tools that are freely available from Microsoft.

PSTools; this is basically a set of tools that let you manage a remote server as if it was a local one.  this contains a number of different commands which are all listed on the website.  I’m going to integrate the PSExec command into the project Build Scripts.

Monday, November 9, 2009

Unit Testing types for developers

Well you all know I'm a big fan of Unit Testing but did you know all the different types of tests you can run?  In this Blog I'll go over some of the examples:

A simple class to test

First we need a simple class to test so I'll use a very, very simple addition and division example called SimpleClass.  It contains two methods Add and Division both of which take two integers and return results.  Here is the basic code....

    public class SimpleClass
    {
        /// <summary>
        /// Add two values
        /// </summary>
        /// <param name="first">first value to add</param>
        /// <param name="second">second value to add</param>
        /// <returns>sum of both values</returns>
        public int Add(int first, int second)
        {
            return first + second;
        }

        /// <summary>
        /// Divide two values
        /// </summary>
        /// <param name="first">first value to divide</param>
        /// <param name="second">second value to divide</param>
        /// <returns>division of both values</returns>
        public decimal Divide(int first, int second)
        {
            return first / second;
        }
    }

Lets get down to the testing.

First off all you need a class decorated with the attribute [TestFixture] this will tell NUnit GUI to run the test from the external program.  Here you can see a basic test thats you've probably see a few times before.

    [TestFixture]
    public class TestingExamples
    {
        [Test(Description="Basic Test")]
        public void SimpleClass_Test_A_Simple_Method()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }
    }

It's saying pass the values 10 and 20 into the Add method and expect to get the result 30.  Simple really, and probably the type of test you'l want to write over and over again.  Howere there are other options available.

Repeat Test

        [Test(Description = "Repeat Test"), Repeat(30)]
        public void SimpleClass_Repeat_Test()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

By adding the Repeat(30) attribute to the test as shown this will run the test 30 times.  In this example it's not really a very useful test but if for example you want to test load on a server or perhaps populate a number of rows in a database it can be very useful.

Multipule Value Test

        [Test(Description="Multivalue Test")]
        [TestCase(10,20,30)]
        [TestCase(1,2,3)]
        [TestCase(7,6,13)]
        public void SimpleClass_TestCase_With_Many_Inputs(int
firstInput, int secondInput, int expectedResult)
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(firstInput, secondInput);
            Assert.IsTrue(result == expectedResult, "Result was not correct!");
        }

Here I'm calling the test 3 times but passing 3 different values and testing against 3 different results.  By using the [TestCase] attribute you can just add more and more values to the same test.

Expected Exception Test

        [Test(Description = "Expected Exception Test")]
        [ExpectedException(typeof(DivideByZeroException),
ExpectedMessage = "divide", MatchType = MessageMatch.Contains)]
        public void SimpleClass_TestCase_Divide_By_Zero()
        {
            SimpleClass simpleClass = new SimpleClass();
            decimal result = simpleClass.Divide(0, 0);
        }

Here is a divide test that throws a divide by Zero error.  By using the ExpectedException attribute we catch the error thrown by the .Net function and then checks it's the correct one, in this case System.DivideByZeroException.  It also checks the message text for the text "divide" and uses the MessageMatch.Contains attribute to indicate the text can exist anywhere in the error message.

Explicit

        [Test(Description = "Only Run when Explicitly chosen"), Explicit]
        public void SimpleClass_Explicit_Test_Of_Method()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

This is an interesting one for us in that it will only run when you "explicitly" select it to run using TestRunner or the Nunit GUI, if not it will be ignored during test runs.  You'd use this function if you wanted to have a UI test or specific test that won't run on the Build server.

MaxTime and TimeOut

        [Test(Description = "Maxtime Test"), MaxTime(20)]
        public void  SimpleClass_Max_Time_In_Mili_Seconds()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

        [Test(Description = "Timeout Test"), Timeout(20)]
        public void SimpleClass_Ensure_Long_Running_Process_Does_Not_Time_Out()
        {
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

Timed tests are great for performance tests, here we specify that both tests need to run within 20 miliseconds.  What's the difference between them?  Well not a lot really so it's probably best to stick to Timeout and ignore MaxTime.

Platform

        [Test(Description = ".Net exclude test"), Platform(Exclude = "NET-2.0")]
        public void SimpleClass_Exclude_DotNet_Tests()
        {
            // Other options relevant to us
            // WinXP, Win2003Server, Vista, Net-1.1, Mono
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(10, 20);
            Assert.IsTrue(result == 30, "Result was not correct!");
        }

Probably not something we'd use very often but it may be useful in the future.  Here we specify that we this test should not be run under .Net 2.  Again the test is not important here what is important is that we can say things like only run a test on a Windows 2003 Server or only run the test on XP.

Random Values

        [Test(Description = "Random value generation test")]
        public void SimpleClass_Random_Values(
            [Values(10, 20, 30)] int firstValue,
            [Random(1, 50, 5)] int secondValue)
        {
            // run 15 times.. 3 values by 5 random numbers
            SimpleClass simpleClass = new SimpleClass();
            int result = simpleClass.Add(firstValue, secondValue);
            int testResult = firstValue + secondValue;
            Assert.IsTrue(result == testResult, "Result was not correct!");
        }

Finally sometimes you just can't be assed coming up with test data so in this case we use the [Random] attribute.  By saying [Random(1,50,5) int ]  I'm saying choose a number between 1 and 50 and run that test 5 times.  I've also added 3 additional [Values] 10,20 and 30 this means the test will run 15 times, i.e. 3 by 5