Skip to content

Test Automation: Programmatic Platform Profiling

Originally Published Wednesday, July 02, 2008

Occasionally, the execution or outcome of a test depends on the operating system version on which the test is executed. Platform profiling is important because subtle differences in operating system platforms can affect how certain tasks are carried out, inclusion or exclusion of specific features or capabilities, work-arounds, or even changes in deterministic or declarative oracles that determines pass, fail, or indeterminate results. For example, accessing certain features on the Vista platform will trigger the User Account Control (UAC) dialog, whereas this feature does not exist on previous versions of Windows.

It is easy for a tester to select the appropriate OS version when executing tests manually and determine the correct steps or settings and determine the correct results of a test based on their cognitive expectations for an outcome, But, in an automated test system where tests are distributed across the wire to various machine configurations and operating system platforms the test designer must programmatically detect the operating system version in automated tests that need to be profiled for the appropriate platform. Programmatic platform profiling negates the need to write several different tests for a single test case that is dependent on variations in the operating system versions. Detecting the operating system version at runtime allows the automation test designer to handle subtle differences between the operating systems within one one test case.

Detecting the major and minor OS versions with C# is relatively straight forward using the System.PlatformID enumeration and the System.Environment.OSVersion property and OperatingSystem class members.

The System.PlatformID enumeration detects the major operating platforms including:

  • Win32Windows – versions of Windows 9x, including Windows ME
  • Win32NT – versions of Windows 2000, Xp, and Vista
  • WinCE – versions of Windows CE
  • Unix – versions of the Unix OS

Once the platform is determined, the test designer can drill down further using the Environment.OSVersion.Version.Major and Environment.OSVerions.Version.Minor members to find the specific major and minor operating system version number. If tests are dependent on specific revisions or service packs of the major operating system then the integer or string values can be obtained using the OSVersion.Version.Revision or OSVersion.Version.Build members to determine  specific versions of an operating system. Some versions of Windows used alphabetic characters in the revision number, so in those cases the revision should be converted to and compared using a string object as represented by the constant values for Windows 95 retail, Windows 95 OSR 2.1 and Windows 95 OSR 2.5 and Windows 98 Second Edition. Also, the OperatingSystem.ServicePack property can be used to determine if, and what service pack has been installed on the operating system.

   1: class OSVersionInfo

   2: {

   3:   /// <summary>

   4:   /// Windows NT Kernel Major Version Numbers

   5:   /// </summary>

   6:   enum Win32NTMajorKernelVersion 

   7:   {

   8:     NT4 = 4,

   9:     NT5 = 5,

  10:     NT6 = 6

  11:   }

  12:  

  13:   /// <summary>

  14:   /// Windows NT Kernel Minor Version Numbers

  15:   /// </summary>

  16:   enum Win32NTMinorKernelVersion

  17:   {

  18:     Win2000 = 0,

  19:     WinXp = 1,

  20:     Win2003Server = 2,

  21:     Vista = 0,

  22:     Win7 = 1

  23:   }

  24:  

  25:   /// <summary>

  26:   /// Windows 9x Kernel Minor Version Numbers

  27:   /// </summary>

  28:   enum Win9xMinorKernelVersion

  29:   {

  30:     Win95 = 0,

  31:     Win95Osr2 = 3,

  32:     Win98 = 10,

  33:     WinME = 90

  34:   }

  35:   

  36:   // Service Pack identification strings

  37:   private const string VistaSp1  = "Service Pack 1";

  38:   private const string Win95Sp1     = "950A";

  39:   private const string Win95Osr2   = "950B";

  40:   private const string Win95Osr25   = "950C";

  41:   private const string Win98SE       = "2222A";

  42:  

  43:   /// <summary>

  44:   /// Detects the current version of the operating system useful for

  45:   /// controlling execution branches in automated test cases that are

  46:   /// platform dependent

  47:   /// </summary>

  48:   /// <returns>A string representing the OS version</returns>

  49:   private static string GetOSVersion()

  50:   {

  51:     OperatingSystem osVersionInfo = Environment.OSVersion;

  52:     string osVersion = string.Empty;

  53:     switch (osVersionInfo.Platform)

  54:     {

  55:       case PlatformID.Win32NT:

  56:         switch (osVersionInfo.Version.Major)

  57:         {

  58:           case (int)Win32NTMajorKernelVersion.NT4:

  59:             osVersion = "NT4";

  60:             break;

  61:           case (int)Win32NTMajorKernelVersion.NT5:

  62:             switch (osVersionInfo.Version.Minor)

  63:             {

  64:               case (int)Win32NTMinorKernelVersion.Win2000:

  65:                 osVersion = "Win2K";

  66:                 break;

  67:               case (int)Win32NTMinorKernelVersion.WinXp:

  68:                 osVersion = "WinXp";

  69:                 break;

  70:               case (int)Win32NTMinorKernelVersion.Win2003Server:

  71:                 osVersion = "Win2003Server";

  72:                 break;

  73:             }

  74:  

  75:             break;

  76:           case (int)Win32NTMajorKernelVersion.NT6:

  77:             switch (osVersionInfo.Version.Minor)

  78:             {

  79:               case (int)Win32NTMinorKernelVersion.Vista:

  80:                 if (osVersionInfo.ServicePack == VistaSp1)

  81:                 {

  82:                   osVersion = "Vista SP1";

  83:                 }

  84:                 else

  85:                 {

  86:                   // Windows Vista or WinServer2008

  87:                   osVersion = "Vista";

  88:                 }

  89:  

  90:                 break;

  91:               case (int)Win32NTMinorKernelVersion.Win7:

  92:                 osVersion = "Windows 7";

  93:                 break;

  94:             }

  95:  

  96:             break;

  97:         }

  98:  

  99:         break;

 100:       // Windows 9x Versions

 101:       case PlatformID.Win32Windows:

 102:         switch (osVersionInfo.Version.Minor)

 103:         {

 104:           // Windows 95, OSR 1.0, OSR 2.0

 105:           case (int)Win9xMinorKernelVersion.Win95:

 106:             if (osVersionInfo.Version.Revision.ToString() == Win95Sp1)

 107:             {

 108:               osVersion = "Windows 95 SP1";

 109:             }

 110:             else if (osVersionInfo.Version.Revision.ToString() == Win95Osr2)

 111:             {

 112:               osVersion = "Windows 95 OSR 2.0";

 113:             }

 114:             else

 115:             {

 116:               osVersion = "Win95";

 117:             }

 118:             break;

 119:           // Windows 95 OSR 2.1, OSR 2.5

 120:           case (int)Win9xMinorKernelVersion.Win95Osr2:

 121:             if (osVersionInfo.Version.Revision.ToString() == Win95Osr2)

 122:             {

 123:               osVersion = "Win95_OSR2.1";

 124:             }

 125:             else if (osVersionInfo.Version.Revision.ToString() == Win95Osr25)

 126:             {

 127:               osVersion = "Win95_OSR2.5";

 128:             }

 129:             break;

 130:           // Windows 98 and Windows 98 Second Edition

 131:           case (int)Win9xMinorKernelVersion.Win98:

 132:             if (osVersionInfo.Version.Revision.ToString() == Win98SE)

 133:             {

 134:               osVersion = "Win98SE";

 135:             }

 136:             else

 137:             {

 138:               osVersion = "Win98";

 139:             }

 140:             break;

 141:           // Windows ME

 142:           case (int)Win9xMinorKernelVersion.WinME:

 143:             osVersion = "WinME";

 144:             break;

 145:         }

 146:  

 147:         break;

 148:     }

 149:  

 150:     return osVersion;

 151:   } 

 152: }

 153:  

Currently, C# does not have a property or method to determine the specific edition of an operating system. If a test is dependent on a specific edition of Windows 2000, Windows Xp, or Windows 2003 operating system edition then we need to invoke the Win32 GetVersionEx() function. If a test is dependent on a specific edition of Windows Vista or Windows Server 2008 then we can invoke the Win32 GetProductInfo() function.

Programmatically detecting the operating system version at runtime enables the test designer to design one test that can execute on a different operating system versions by allowing for specific control flow of a test based on the operating system the test is running. Programmatic platform profiling also negates the need to rewrite the same fundamental test over and over again to handle differences in behavior or expectations of operating system versions. It can also reduce some long term costs of test case maintenance, give the test designer greater control over the execution of an automated test, and increases the reusability and the maintainability of a test case that must be ran on multiple operating system versions.

Quite simply, programmatic platform profiling is a best practice in software test automation when a given test is dependent on the profile of the platform on which it is executing!

2 Comments

  1. testingmentor wrote:

    Hi,

    Which approach below are you using typically and what do you recommend?

    [pseudo code]

    #1 Test code branches

    strOS = GetOSVersion

    If strOS = “Win95″ Then RunTestWin95

    #2 Common test code with OS-dependant run-time specific handling

    strOS = GetOSVersion

    RunTest (strOS)

    Function RunTest (strOS)

    If strOS = “Win95″ Then…

    End Function

    I use #2 with our main AUT using GetAUTVersion within a test case but I am curious what is regarded as recommended best practice in this area.

    Wednesday, July 02, 2008 9:33 AM by stth10

    Wednesday, November 18, 2009 at 7:06 PM | Permalink
  2. testingmentor wrote:

    Hi Stth10,

    I agree with you that option #2 (common code with OS dependent runtime handling) is a better practice as it would make maintainability of the code much easier and have less redundancy.

    Thursday, July 03, 2008 9:49 AM by I.M.Testy

    Wednesday, November 18, 2009 at 7:06 PM | Permalink

One Trackback/Pingback

  1. [...] 2 years ago I described a way to get the operating system version information using the System.PlatformID enumeration and the [...]