Using Partial Clones for TDD and Polymorphism in PowerShell

by Klaus Graefensteiner 3. December 2009 07:41

Introduction

I am working on a top secret PowerShell project at the moment. One of the functions that I am writing returns a list of FileInfo objects. These objects get then get passed into another function, which analyzes file names and extensions and dispatches different actions in a wildcard enabled switch statement. I am using PSUnit as unit testing framework.

To make the second function more testable, I wanted to avoid using FileInfo objects as parameters and came up with the idea to clone the FileInfo objects and use only the parameters that my script would actually use. My function now takes as input a list of custom PSObjects instead of FileInfo objects. This makes the function much more testable and the overall design a little more decoupled.

cameleon-small

Figure 1: A Plain Old Chameleon

In this Post

The subject of this post is an Advanced PowerShell function that converts any object into a custom PowerShell object. The cloning only considers the property names that are passed in as a parameter to the function. The article covers the following PowerShell features:

  • Advanced Functions
  • Parameter Sets
  • Add-Member ScriptMethod

As an additional feature of my function I wanted first to preserve the type name of the original object. This way I would later be able to recreate the original object based on the type name and, in the case of the FileInfo object, the FullName property. But then I thought that I could actually go the whole nine yards by telling the new clone how to convert itself back to its original object. For this I created a ScriptMethod member that knows how to revert the cloned object back to a FileInfo object. The ScriptMethod member of course is called “Revert”.

TDD and Polymorphism

I found the technique of creating partial clones and getting rid of the dependency to an actual file quite helpful doing TDD (Test Driven Development) in PowerShell. Also I also discovered that it is quite easy to use Polymorphism in PowerShell by specializing a common Member via a function parameter. In this case the Revert ScriptMethod member can do anything necessary to convert the clone back to its original source object.

PowerShell Script

function Clone-AsStub()
{
    [CmdletBinding(DefaultParameterSetName="Full")]
    param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [PSObject] $ObjectToClone,

        [Parameter(Position=1, Mandatory=$false, ValueFromPipeline=$false)]
        [ValidateScript( {$_ -ne $Null -and $_.Length -gt 0})]
        [string[]] $PropertiesToClone,
        
        [Parameter(Position=2, Mandatory=$false, ValueFromPipeline=$false)]
        [switch] $PreserveTypeInfo,
        
        [Parameter(Position=3, Mandatory=$false, ValueFromPipeline=$false, ParameterSetName="Magic")]
        [ScriptBlock] $RevertScriptBlock

    )
    process
    {
        
        $PropertyTable = @{}
        foreach($Prop in $PropertiesToClone)
        {
            $PropertyTable[$Prop] = $ObjectToClone.$Prop
        }
        
        if($PreserveTypeInfo)
        {
            $PropertyTable["TypeName"] = $ObjectToClone.GetType().FullName
        }
        
        $Clone = New-Object -TypeName "System.Management.Automation.PSObject" `
                            -Property $PropertyTable
        
        if( $PsCmdlet.ParameterSetName -eq "Magic")
        {
            $Clone = Add-Member -InputObject $Clone `
                                -MemberType "ScriptMethod" `
                                -Name "Revert" `
                                -Value $RevertScriptBlock `
                                -PassThru
        }
        return $Clone
    }
}

$FI = get-Item "C:\Spices.txt"
$FI
$FI.GetType().Fullname

$Result = $FI | Clone-AsStub -PropertiesToClone "Name", "FullName", "Extension", "LastWriteTime"
$Result

$Result = $FI | Clone-AsStub -PropertiesToClone "Name", "FullName", "Extension", "LastWriteTime" `
                             -PreserveTypeInfo
$Result

$Result = $FI | Clone-AsStub -PropertiesToClone "Name", "FullName", "Extension", "LastWriteTime" `
                             -PreserveTypeInfo `
                             -RevertScriptBlock {Get-Item -Path $This.FullName}
$Result

$FI = $Result.Revert()
$Result | Get-member
$FI.GetType().FullName

Download

The script file can be downloaded here: CloneAsStubStudy.zip

Ausblick

All I can say is that I am still having fun writing solutions in PowerShell.

Tags: , , , ,

PSUnit | PowerShell | Test Automation | Tips & Tricks

Comments

12/3/2009 10:53:14 AM #

pingback

Pingback from topsy.com

Twitter Trackbacks for
        
        Tellingmachine | Using Partial Clones for TDD and Polymorphism in PowerShell
        [tellingmachine.com]
        on Topsy.com

topsy.com | Reply

Add comment




  Country flag

biuquote
  • Comment
  • Preview
Loading



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 at Rockwell Automation and is founder of the PowerShell Unit Testing Framework PSUnit. More...

Administration

About

Powered by:
BlogEngine.Net
Version: 1.5.0.7

License:
Creative Commons License

Copyright:
© Copyright 2009, 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 2009 by Klaus Graefensteiner

Rendertime:
Page rendered at 9/8/2010 9:08:51 AM (PST Pacific Standard Time UTC DST -7)