Generating NUnit tests with PowerShell

by Klaus Graefensteiner 3. March 2009 06:27

Introduction

The other day I needed to write NUnit unit tests to for a large number of method overloads. There were almost 100 methods that needed to be tested. The method signatures followed a well defined pattern. This didn’t look like much fun at first, but then I looked in my toolbox and I saw the smiling face of the PowerShell ISE shouting “Pick me! Pick me!”. About two hours later I had created a script that would parse the method signatures and generate NUnit test methods for each of the functions.

Schaufelradbagger 

Figure 1: Schaufelradbagger

C# source code

The following listing shows the methods that needed unit tests. The source file is just an example that demonstrates the kind of methods that the PowerShell script can process.

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4:  
   5: namespace StaceTravel
   6: {
   7:     public class TimeWarp
   8:     {
   9:         static TimeWarp()
  10:         { }
  11:  
  12:         //This is just a short collection of functions that my PowerShell script parses and provides NUnit tests for
  13:  
  14:         public static string GetTimeWarp(DateTime date)
  15:         {
  16:             return date.ToShortDateString();
  17:         }
  18:  
  19:         public static int GetSecondsPastTimeWarp(DateTime date)
  20:         {
  21:             return date.Second;
  22:         }
  23:  
  24:         public static int GetMinutesPastTimeWarp(DateTime date)
  25:         {
  26:             return date.Minute;
  27:         }
  28:  
  29:         public static bool IsTooLate(DateTime date)
  30:         {
  31:             return true;
  32:         }
  33:  
  34:         public static DateTime NextAvailabeWormhole(DateTime date)
  35:         {
  36:             return date;
  37:         }
  38:  
  39:         public static int NumberOfPossibleTimeWarps(string date1, string date2)
  40:         {
  41:             return 3;
  42:         }
  43:  
  44:         public static int NumberOfPossibleTimeWarps(DateTime date1, DateTime date2)
  45:         {
  46:             return 2;
  47:         }
  48:  
  49:         public static string GetNameOfTargetSystem(string date, int jumps)
  50:         {
  51:             return "Forest";
  52:         }
  53:  
  54:         public static string GetNameOfTargetSystem(DateTime date, int jumps)
  55:         {
  56:             return "Lake";
  57:         }
  58:  
  59:     }
  60: }

PowerShell script

The main task of the PowerShell script is to parse the signature of public static methods including the return type and the names of the function parameters. Based on this information the PowerShell script would then write the NUnit test source code to the output file.

PowerShell ISE in action

Figure 2: PowerShell ISE in action

   1: CLS
   2: $Lines = Get-Content -path "C:\Users\Klaus\Desktop\TimeWarp.cs"
   3: $UnitTestCode = ""
   4: $C = ""
   5: #Get public static function names <FN>, return types <RT> and parameters <PS>
   6: $Lines | foreach-object `
   7: {
   8:     if ($_ -match  '^(\s*public\s+static\s+)(?<RT>(.+?))\s+(?<FN>(.+?))\((?<PS>(.+?))\)(\s*)$')
   9:     {  
  10:         $C = ""
  11:         $Matches.RT + " " + $Matches.FN + " " +$Matches.PS
  12:         #Store matches in variables because the next regex execution will replace them
  13:         $FN = $Matches.FN;
  14:         $RT = $Matches.RT;
  15:         $PS = $Matches.PS;
  16:         $C += "`t`t/// <summary>`n"
  17:         $C += "`t`t/// Test $FN should not blow up`n"
  18:         $C += "`t`t/// </summary>`n"
  19:         $C += "`t`t[Test]`n"
  20:         $Overload = ""
  21:         $Parameters = $PS.Split(",");
  22:         foreach( $s in $Parameters)
  23:         {
  24:             $s = $s.TrimStart().TrimEnd();
  25:             # This regex execution will override the former execution and its $matches hashtable
  26:             switch -regex ($s)
  27:             {
  28:                 'string\s'    { $Overload += "string" }
  29:                 'DateTime\s'  { $Overload += "DateTime" }
  30:             }   
  31:         }
  32:         $C += "`t`tpublic void TimeWarp$($FN)From$($Overload)ShouldNotBlowUp`(`)`n"
  33:         $C += "`t`t{`n"
  34:         $C += "`t`t`t$RT returnValue;`n"
  35:         $Parameters = $PS.Split(",");
  36:         foreach( $s in $Parameters)
  37:         {
  38:             $s = $s.TrimStart().TrimEnd();
  39:             # This regex execution will override the former execution and its $matches hashtable
  40:             switch -regex ($s)
  41:             {
  42:                 'int\s'       { $C += "`t`t`t$s = 4;`n" }
  43:                 'string\s'    { $C += "`t`t`t$s = DateTime.Now.ToString();`n" }
  44:                 'DateTime\s'  { $C += "`t`t`t$s = DateTime.Now;`n" }
  45:             }   
  46:         }
  47:         $ParameterNames = $PS.Replace("string ", "").Replace("int ", "").Replace("DateTime", "")
  48:         $C += "`t`t`treturnValue = TimeWarp.$($FN)`($ParameterNames`);`n"
  49:         $C += "`t`t`tAssert.IsNotNull(returnValue);`n"
  50:         $C += "`t`t}`n`n`n"
  51:         $UnitTestCode += $C
  52:     }
  53: }
  54:  
  55: Set-content -Path "C:\Users\Klaus\Desktop\TimeWarpTest.cs" -Force -Value $UnitTestCode
  56:  
  57:  
  58:  
  59:  

NUnit test methods

The PowerShell script doesn’t create the whole unit test class, but generates just the test methods, which I copy and pasted into my Visual Studio test project. The following code snippet shows the output of my PowerShell script.

   1: /// <summary>
   2: /// Test GetTimeWarp should not blow up
   3: /// </summary>
   4: [Test]
   5: public void TimeWarpGetTimeWarpFromDateTimeShouldNotBlowUp()
   6: {
   7:     string returnValue;
   8:     DateTime date = DateTime.Now;
   9:     returnValue = TimeWarp.GetTimeWarp( date);
  10:     Assert.IsNotNull(returnValue);
  11: }
  12:  
  13:  
  14: /// <summary>
  15: /// Test GetSecondsPastTimeWarp should not blow up
  16: /// </summary>
  17: [Test]
  18: public void TimeWarpGetSecondsPastTimeWarpFromDateTimeShouldNotBlowUp()
  19: {
  20:     int returnValue;
  21:     DateTime date = DateTime.Now;
  22:     returnValue = TimeWarp.GetSecondsPastTimeWarp( date);
  23:     Assert.IsNotNull(returnValue);
  24: }
  25:  
  26:  
  27: /// <summary>
  28: /// Test GetMinutesPastTimeWarp should not blow up
  29: /// </summary>
  30: [Test]
  31: public void TimeWarpGetMinutesPastTimeWarpFromDateTimeShouldNotBlowUp()
  32: {
  33:     int returnValue;
  34:     DateTime date = DateTime.Now;
  35:     returnValue = TimeWarp.GetMinutesPastTimeWarp( date);
  36:     Assert.IsNotNull(returnValue);
  37: }
  38:  
  39:  
  40: /// <summary>
  41: /// Test IsTooLate should not blow up
  42: /// </summary>
  43: [Test]
  44: public void TimeWarpIsTooLateFromDateTimeShouldNotBlowUp()
  45: {
  46:     bool returnValue;
  47:     DateTime date = DateTime.Now;
  48:     returnValue = TimeWarp.IsTooLate( date);
  49:     Assert.IsNotNull(returnValue);
  50: }
  51:  
  52:  
  53: /// <summary>
  54: /// Test NextAvailabeWormhole should not blow up
  55: /// </summary>
  56: [Test]
  57: public void TimeWarpNextAvailabeWormholeFromDateTimeShouldNotBlowUp()
  58: {
  59:     DateTime returnValue;
  60:     DateTime date = DateTime.Now;
  61:     returnValue = TimeWarp.NextAvailabeWormhole( date);
  62:     Assert.IsNotNull(returnValue);
  63: }
  64:  
  65:  
  66: /// <summary>
  67: /// Test NumberOfPossibleTimeWarps should not blow up
  68: /// </summary>
  69: [Test]
  70: public void TimeWarpNumberOfPossibleTimeWarpsFromstringstringShouldNotBlowUp()
  71: {
  72:     int returnValue;
  73:     string date1 = DateTime.Now.ToString();
  74:     string date2 = DateTime.Now.ToString();
  75:     returnValue = TimeWarp.NumberOfPossibleTimeWarps(date1, date2);
  76:     Assert.IsNotNull(returnValue);
  77: }
  78:  
  79:  
  80: /// <summary>
  81: /// Test NumberOfPossibleTimeWarps should not blow up
  82: /// </summary>
  83: [Test]
  84: public void TimeWarpNumberOfPossibleTimeWarpsFromDateTimeDateTimeShouldNotBlowUp()
  85: {
  86:     int returnValue;
  87:     DateTime date1 = DateTime.Now;
  88:     DateTime date2 = DateTime.Now;
  89:     returnValue = TimeWarp.NumberOfPossibleTimeWarps( date1,  date2);
  90:     Assert.IsNotNull(returnValue);
  91: }
  92:  
  93:  
  94: /// <summary>
  95: /// Test GetNameOfTargetSystem should not blow up
  96: /// </summary>
  97: [Test]
  98: public void TimeWarpGetNameOfTargetSystemFromstringShouldNotBlowUp()
  99: {
 100:     string returnValue;
 101:     string date = DateTime.Now.ToString();
 102:     int jumps = 4;
 103:     returnValue = TimeWarp.GetNameOfTargetSystem(date, jumps);
 104:     Assert.IsNotNull(returnValue);
 105: }
 106:  
 107:  
 108: /// <summary>
 109: /// Test GetNameOfTargetSystem should not blow up
 110: /// </summary>
 111: [Test]
 112: public void TimeWarpGetNameOfTargetSystemFromDateTimeShouldNotBlowUp()
 113: {
 114:     string returnValue;
 115:     DateTime date = DateTime.Now;
 116:     int jumps = 4;
 117:     returnValue = TimeWarp.GetNameOfTargetSystem( date, jumps);
 118:     Assert.IsNotNull(returnValue);
 119: }

NUnit Test Run

Figure 3: NUnit test runner with automatically generated test methods

Download

All files discussed in this article and the complete Visual Studio 2008 project can be downloaded here: Export-NUnitTest.zip

Ausblick

I guess there are other ways to generate the test method stubs, but not a lot of tools generate the actual implementation of the test methods too. Another great example for the usefulness of PowerShell.

Tags: ,

.NET Framework | Test Automation | PowerShell

Comments are closed

About Klaus Graefensteiner

I like the programming of machines.

Add to Google Reader or Homepage

LinkedIn FacebookTwitter View Klaus Graefensteiner's profile on Technorati
Klaus Graefensteiner

Klaus Graefensteiner
works as Developer In Test and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Open Source Projects

PSUnit is a Unit Testing framwork for PowerShell. It is designed for simplicity and hosted by Codeplex.
BlogShell is The tool for lazy developers who like to automate the composition of blog content during the writing of a blog post. It is hosted by CodePlex.

Administration

About

Powered by:
BlogEngine.Net
Version: 1.6.1.0

License:
Creative Commons License

Copyright:
© Copyright 2014, Klaus Graefensteiner.

Disclaimer:
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Theme design:
This blog theme was designed and is copyrighted 2014 by Klaus Graefensteiner

Rendertime:
Page rendered at 8/1/2014 5:22:09 PM (PST Pacific Standard Time UTC DST -7)