Brian Hartsock's Blog

Using Pipeline.Input for Powershell testing

by bhartsock on Mar.30, 2009, under Uncategorized

Last week, I posted about how to unit test powershell, which I have been working with a little bit over the weekend. One thing I quickly realized was testing interaction with the pipeline is a must for Powershell. It’s pretty easy to do.

Let’s start with the Get-Service cmdlet that ships with Powershell. If you load up reflector, you will see the follow class definition.

[Cmdlet("Get", "Service", DefaultParameterSetName="Default")]
public sealed class GetServiceCommand : MultipleServiceCommandBase
{
    // Methods
    public GetServiceCommand();
    protected override void ProcessRecord();
 
    // Properties
    [Parameter(Position=0, 
          ParameterSetName="Default", 
          ValueFromPipelineByPropertyName=true, 
          ValueFromPipeline=true),
     Alias(new string[] { "ServiceName" })]
    public string[] Name { get; set; }
}

Remembering the base test fixture from the previous post on TDD in Powershell, I can quickly write up a few tests that test a few different use cases of the get-service cmdlet with

 
[Test]
public void Get_Service_with_single_string_in_pipeline() 
{
    // "MySQL" | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(name);
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
[Test]
public void Get_Service_with_single_object_in_pipeline_using_Name_property()
{
    //New-Object PSObject | Add-Member NoteProperty Name "MySQL" -PassThru | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(new { Name = name });
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
[Test]
public void Get_Service_with_single_object_in_pipeline_using_ServiceName_property()
{
    //New-Object PSObject | Add-Member NoteProperty ServiceName "MySQL" -PassThru | get-service
 
    var name = "MySQL";
 
    var pipeline = Runspace.CreatePipeline();
 
    pipeline.Input.Write(new { ServiceName = name });
    pipeline.Commands.Add("get-service");
 
    var result = pipeline.Invoke();
 
    AssertThatPipelineResultIsService(result, name);
}
 
private void AssertThatPipelineResultIsService(Collection<PSObject> result, string name)
{
    Assert.That(result.Count == 1);
    Assert.That(result[0].BaseObject is ServiceController);
    Assert.That((result[0].BaseObject as ServiceController).ServiceName == name);
}

By using pipeline.Input.Write(), I can write to the pipeline before invoking commands. Really easy to do, and super useful, because each Powershell cmdlet can probably be called a bunch of different ways.

Where can you use it? Snap in development or testing your own Powershell scripts. Stop guessing how the pipeline is going to work and test it.

Post to Twitter Post to Digg Post to Facebook Post to Reddit

:, , ,

Leave a Reply

Post by day

March 2009
M T W T F S S
« Feb   Apr »
 1
2345678
9101112131415
16171819202122
23242526272829
3031