TDD with Powershell, from the client perspective

Is it possible? Yes, and it is actually relatively easy. The hardest part can be figuring out how to mock/stub out certain functionality so your testing small units as opposed to full acceptance testing. The line can get blurry, but I don’t really care. Testing is half the battle.

But to be clear, the focus of my testing is to test how a snap-in is working. It sounds like an integration test, and maybe it is, but there is no reason you couldn’t test any powershell script using some of the steps outlined here. Just be flexible and creative.

Start by creating a nice base test fixture.

public abstract class PowershellTestFixture
{
    protected Runspace Runspace { get; set; }

    public void CreateRunspace()
    {
        Runspace = RunspaceFactory.CreateRunspace(CreateConfiguration());
        Runspace.Open();           
    }

    public void CloseRunspace()
    {
        Runspace.Close();
        Runspace.Dispose();
    }

    private RunspaceConfiguration CreateConfiguration()
    {
        var config = RunspaceConfiguration.Create();

        PSSnapInException warning;
        config.AddPSSnapIn("SomeCustomSnapIn", out warning);

        return config;
    }

    protected Collection<psobject> ExecutePowershell(string script)
    {
        return Runspace.CreatePipeline(script).Invoke();
    }
}

In this base class, I just created some nice helper methods, and one method that samples how to add a snap-in to the runspace.

Now, just write a test, and add your assertions. And it will work!

[TestFixture]
public class TestSomethingStupid : PowershellTestFixture
{
    [SetUp]
    public void Setup()
    {
        CreateRunspace();
    }

    [TearDown]
    public void TearDown()
    {
        CloseRunspace();
    }

    [Test]
    public void GetServiceWhereNameIsMySql()
    {
        string cmd = @"
get-service | where { $_.name -eq 'MySQL' }
";
        var result = ExecutePowershell(cmd)
            .Select(o => o.BaseObject)
            .Cast<system.serviceprocess.servicecontroller>()
            .First();

        Assert.AreEqual(result.ServiceName, "MySQL");            
    }
}

Obviously this test is stupid. But that’s not the point. In a very few lines, I have tested the output of some powershell. Pretty cool if you ask me, especially if your coding a snap in. If you aren’t automating the tests, how else can you verify it works except to recompile, install, open powershell, and type some code? Very slow and painful!

It is important to note, there are other ways to test snap-in’s. What I really wanted to see is how my cmdlet’s looked from the powershell perspective, not the C# perspective.