# Wednesday, July 18, 2007

I’ve recently done some research into .NET WinForms testing on behalf of a customer and there are several different levels which we can attack this. Each is of different complexity and cost.

Simulate Mouse Clicks and Keyboard Presses

This method has been around since Windows 3.1 days and involves heavy use of SendKeys and SendMessage to manipulate Window message queue to send mouse and keyboard events directly. An old but pretty good sample is at http://msdn.microsoft.com/msdnmag/issues/02/03/Bugslayer/.

Drive Forms Controls Directly

The next simplest method is to get hold of Windows forms controls directly so you can call methods and set properties using code. This method usually involves running the target forms within your own process. The following two MSDN magazine articles describe the steps:

The second one looks at how to cancel message boxes etc by sending messages directly to the window. Both articles describe the method but they are not very user friendly and you will have to write a fair amount of code. Fortunately there is a library available that hooks into the NUnit testing framework at http://nunitforms.sourceforge.net/. Still lots of code but you get to write higher level stuff such as:

ButtonTester button = new ButtonTester("nameOfSomeButton");
button.Click();
Assert.Equals(“Clicked!”,  button.Text);

The only problem I can see with this is maybe development has stopped as the last full release was in November 2004 with a few alphas up until May 2006. Still you can grab the source and start hacking away if there are any problems.

Using Active Accessibility 2.0

This API has been around for a few years and is a standard way of controlling all Windows controls. The trouble is though that it’s a COM API and somewhat complex to master. I’ve seen anecdotes on the Internet talking about the test code being more complex than the application code when using this. For completeness the API is documented at http://msdn2.microsoft.com/en-us/library/ms697707.aspx though the following section has a more modern way of doing this. A walkthrough is available showing how to make a .NET application accessible at http://msdn2.microsoft.com/en-us/library/cb35a5fw(vs.80).aspx.

Using UI Automation

UI Automation is the successor to Active Accessibility and, unlike Active Accessibility, was specifically designed with automation in mind. It’s described in more detail at http://msdn2.microsoft.com/en-us/library/aa348551.aspx with a complete walkthrough and sample code at http://msdn.microsoft.com/msdnmag/issues/07/03/Bugslayer/default.aspx. One thing to note though – the UI Automation bits are only available on computers with .NET 3.0 installed – i.e. Vista, Windows XP and Windows Server 2003.

There is also a very useful library available to help with the code at http://www.codeplex.com/uapp.

Third Party Tools

This wouldn’t be complete without a nod to some of the commercial offerings out there. I haven’t used any since Rational Test many years ago which was next to useless but I hear reasonably good things about Mercury QuickTest Professional though I have no idea how much it costs. There is even a virtual lab available on Automating Testing of Windows Forms Application with TestComplete and Visual Studio 2005 Team System.

Conclusions

To summarize, I would recommend trying NUnitForms and UI Automation to see how you get on with both of them and making a choice between the two. QuickTest Professional will probably be too costly and the other two technologies are a lot of work and too old to consider for all your testing – they may have tactical uses though.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, July 18, 2007 7:52:52 AM (GMT Daylight Time, UTC+01:00)  #    Comments [1] Trackback
# Sunday, July 08, 2007
Monowall
Monowall, uploaded to Flickr by James Snape.

Canon 400D, Canon 24-105 f/4L IS lens - 1/60 second, f/4, ISO 100

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Sunday, July 08, 2007 3:27:19 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Saturday, July 07, 2007
Blue Crossing
Blue Crossing, uploaded to Flickr by James Snape.

Canon 400D, Canon 24-105 f/4L IS lens - 1/10 second, f/11, ISO 100

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Saturday, July 07, 2007 3:24:06 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Friday, July 06, 2007
Red Limit
Red Limit, uploaded to Flickr by James Snape.

Canon 400D, Canon 24-105 f/4L IS lens - 1/30 second, f/4, ISO 100

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Friday, July 06, 2007 3:20:52 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Thursday, July 05, 2007
Red Collection
Red Collection, uploaded to Flickr by James Snape.

Canon 400D, Canon 24-105 f/4L IS lens - 1/60 second, f/4, ISO 100

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Thursday, July 05, 2007 3:17:00 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Wednesday, July 04, 2007
Tony Blair takes residence in Connaught Square
Tony Blair takes residence in Connaught Square, uploaded to Flickr by James Snape.

This is the moment that Tony Blair moved into Connaught Square at the weekend during our engagement party. Unfortunately I didn't have a paparazzi style long lens on the camera so couldn't get a really tight shot.

Canon 400D, Canon 24-105 f/4L IS lens - 1/250 second, f/4, ISO 400

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, July 04, 2007 1:22:08 PM (GMT Daylight Time, UTC+01:00)  #    Comments [1] Trackback
# Wednesday, June 27, 2007

As everyone knows Tony Blair resigned as Prime Minister and member of parliament today.

He'll be moving into his new house soon and turned up to the residents garden party. My sister lives in the same square and the Daily Mail managed catch her in the background when snapping pictures of him.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, June 27, 2007 10:53:13 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Tuesday, June 19, 2007

The results of the previous three tests are interesting. In both IE7 and Firefox all three render correctly (although the PRE tag in the first one causes the text to spill into the right hand bar). When viewing the RSS feed it becomes a whole new story:

  • IE7 doesn't honor PRE tags, single spaces or stylesheets
  • Firefox doesn't honor PRE tags, single spaces or stylesheets as well but at least it cuts out the embedded stylesheet in the last post
  • Google Reader also doesn't honor PRE tags, single spaces or stylesheets and to cap it all anything in a PRE tag just renders to the end of line and stops so it makes things impossible to read

I wonder, is there a standard that feed readers need to adhere to? What is the best way of embedding syntax colored code in blog posts?

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 19, 2007 5:14:50 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback

Same post but with embedded styles.

I'm trying to get a decent solution to inserting code in blog articles so the next few posts are all about the code. The sample below is a simple line counter tool I use to work out some metrics for code reviews.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace LineCount
{
  class Program
  {
    private static int folders;
    private static int files;
    private static int lines;
    private static int code;
    private static int comments;

    static void Main(string[] args)
    {
      if (args.Length == 0)
      {
        Console.WriteLine(@"
Usage: linecount <root folder>

e.g. linecount t:\dev\projects\main

NB: Only .cs files are considered
  Review time is hard coded to 200 lines per hour
"
);
        return;
      }

      CountLines(new DirectoryInfo(args[0]));

      Console.WriteLine("FOLDERS:{0} FILES:{1} LOC:{2} SLOC:{3} COMMENTS:{4}",
        folders, files, lines, code, comments);
      Console.WriteLine("Code density: {0:p}",
        (double)code / (double)lines);
      Console.WriteLine("Comment density: {0:p}",
        (double)comments / (double)lines);
      Console.WriteLine("Comment ratio: {0:p}",
        (double)comments / (double)code);
      Console.WriteLine("Estimated review time: {0}h", 1+ (code / 200));
    }

    private static void CountLines(DirectoryInfo parent)
    {
      ++folders;

      foreach (DirectoryInfo folder in parent.GetDirectories())
      {
        CountLines(folder);
      }

      foreach (FileInfo file in parent.GetFiles())
      {
        CountLines(file);
      }
    }

    private static void CountLines(FileInfo file)
    {
      switch (file.Extension)
      {
        case ".cs":
          break;
        default:
          return;
      }

      ++files;

      using (StreamReader reader = file.OpenText())
      {
        string line = null;
        bool inComment = false;

        while ((line = reader.ReadLine()) != null)
        {
          ++lines;
          line = line.Trim();

          if (line.Length == 0)
            continue;

          if (line.StartsWith("//"))
          {
            if (line.Replace("//", "").Trim().Length > 0)
              ++comments;

            continue;
          }

          if (line.StartsWith("/*"))
            ++comments;
          else if (!inComment)
            ++code;

          if (line.Contains("/*"))
          {
            inComment = true;
          }

          if (inComment && line.Contains("*/"))
          {
            inComment = false;
          }
        }
      }
    }
  }
}
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 19, 2007 4:34:25 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback

Same post but without the PRE tags:

I'm trying to get a decent solution to inserting code in blog articles so the next few posts are all about the code. The sample below is a simple line counter tool I use to work out some metrics for code reviews.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace LineCount
{
  class Program
  {
    private static int folders;
    private static int files;
    private static int lines;
    private static int code;
    private static int comments;

    static void Main(string[] args)
    {
      if (args.Length == 0)
      {
        Console.WriteLine(@"
Usage: linecount <root folder>

e.g. linecount t:\dev\projects\main

NB: Only .cs files are considered
  Review time is hard coded to 200 lines per hour
"
);
        return;
      }

      CountLines(new DirectoryInfo(args[0]));

      Console.WriteLine("FOLDERS:{0} FILES:{1} LOC:{2} SLOC:{3} COMMENTS:{4}",
        folders, files, lines, code, comments);
      Console.WriteLine("Code density: {0:p}",
        (double)code / (double)lines);
      Console.WriteLine("Comment density: {0:p}",
        (double)comments / (double)lines);
      Console.WriteLine("Comment ratio: {0:p}",
        (double)comments / (double)code);
      Console.WriteLine("Estimated review time: {0}h", 1+ (code / 200));
    }

    private static void CountLines(DirectoryInfo parent)
    {
      ++folders;

      foreach (DirectoryInfo folder in parent.GetDirectories())
      {
        CountLines(folder);
      }

      foreach (FileInfo file in parent.GetFiles())
      {
        CountLines(file);
      }
    }

    private static void CountLines(FileInfo file)
    {
      switch (file.Extension)
      {
        case ".cs":
          break;
        default:
          return;
      }

      ++files;

      using (StreamReader reader = file.OpenText())
      {
        string line = null;
        bool inComment = false;

        while ((line = reader.ReadLine()) != null)
        {
          ++lines;
          line = line.Trim();

          if (line.Length == 0)
            continue;

          if (line.StartsWith("//"))
          {
            if (line.Replace("//", "").Trim().Length > 0)
              ++comments;

            continue;
          }

          if (line.StartsWith("/*"))
            ++comments;
          else if (!inComment)
            ++code;

          if (line.Contains("/*"))
          {
            inComment = true;
          }

          if (inComment && line.Contains("*/"))
          {
            inComment = false;
          }
        }
      }
    }
  }
}
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 19, 2007 4:27:52 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback

I'm trying to get a decent solution to inserting code in blog articles so the next few posts are all about the code. The sample below is a simple line counter tool I use to work out some metrics for code reviews.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace LineCount
{
    class Program
    {
        private static int folders;
        private static int files;
        private static int lines;
        private static int code;
        private static int comments;

        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine(@"
Usage: linecount <root folder>

e.g. linecount t:\dev\projects\main

NB: Only .cs files are considered
    Review time is hard coded to 200 lines per hour
");
                return;
            }

            CountLines(new DirectoryInfo(args[0]));

            Console.WriteLine("FOLDERS:{0} FILES:{1} LOC:{2} SLOC:{3} COMMENTS:{4}", 
                folders, files, lines, code, comments);
            Console.WriteLine("Code density: {0:p}", 
                (double)code / (double)lines);
            Console.WriteLine("Comment density: {0:p}", 
                (double)comments / (double)lines);
            Console.WriteLine("Comment ratio: {0:p}", 
                (double)comments / (double)code);
            Console.WriteLine("Estimated review time: {0}h", 1+ (code / 200));
        }

        private static void CountLines(DirectoryInfo parent)
        {
            ++folders;

            foreach (DirectoryInfo folder in parent.GetDirectories())
            {
                CountLines(folder);
            }

            foreach (FileInfo file in parent.GetFiles())
            {
                CountLines(file);
            }
        }

        private static void CountLines(FileInfo file)
        {
            switch (file.Extension)
            {
                case ".cs":
                    break;
                default:
                    return;
            }

            ++files;

            using (StreamReader reader = file.OpenText())
            {
                string line = null;
                bool inComment = false;

                while ((line = reader.ReadLine()) != null)
                {
                    ++lines;
                    line = line.Trim();

                    if (line.Length == 0)
                        continue;

                    if (line.StartsWith("//"))
                    {
                        if (line.Replace("//", "").Trim().Length > 0)
                            ++comments;

                        continue;
                    }

                    if (line.StartsWith("/*"))
                        ++comments;
                    else if (!inComment)
                        ++code;

                    if (line.Contains("/*"))
                    {
                        inComment = true;
                    }

                    if (inComment && line.Contains("*/"))
                    {
                        inComment = false;
                    }
                }
            }
        }
    }
}
by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Tuesday, June 19, 2007 3:54:31 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0] Trackback
# Wednesday, June 13, 2007
Digg This!
Digg This!, uploaded to Flickr by James Snape.

Canon 400D, Canon 24-105 f/4L IS lens - 1/500 second, f/4, ISO 100

It should be noted that I'm not very good at naming things so if you can come up with a better title for this picture I'd appreciate it.

by This posting is provided "AS IS" with no warranties, and confers no rights.
posted on Wednesday, June 13, 2007 8:14:54 PM (GMT Daylight Time, UTC+01:00)  #    Comments [5] Trackback