Monday, January 19, 2015

Creating your own unit testing framework for PowerShell - part 5


PowerShell cmdlets and modules can report two kinds or errors (Terminating and non-terminating). Terminating errors are errors that cause the pipeline to be terminated immediately, or errors that occur when there is no reason to continue processing. Nonterminating errors are those errors that report a current error condition, but the cmdlet can continue to process input objects. With nonterminating errors, the user is typically notified of the problem, but the cmdlet continues to process the next input object. Terminating errors are reported by throwing exceptions or by calling the ThrowTerminatingError method, while non-terminating errors are reported by calling the Write-Error method that in turn sends an error record to the error stream.
To capture all the non-terminating errors you have to probe the PowerShell.Streams.Error collection and collect the details of the errors. While terminating errors are throw as RuntimeException and can be handled at the catch block.
In our framework, I’ve extended the FunctionInfo object to expose a property to capture non-terminating errors and also provided an option to expose the non-terminating error as a RuntimeException if needed by using the FailOnNonTerminatingError method.
public PsHost FailOnNonTerminatingError()
{
    _failOnNonTerminatingError = true;
    return this;
}

The implementation for the handle errors looks like
private string HandleNonTerminatingErrors(System.Management.Automation.PowerShell shell)
{
    var errors = shell.Streams.Error;
    if (errors == null || errors.Count <= 0) return String.Empty;
    var errorBuilder = new StringBuilder();
    foreach (var err in errors)
    {
        errorBuilder.AppendLine(err.ToString());
    }
    if (_failOnNonTerminatingError)
    {
        throw new RuntimeException(errorBuilder.ToString());
    }
    return errorBuilder.ToString();
}

Now in the code, you can use the test methods as.
[TestMethod]
[ExpectedException(typeof (RuntimeException))]
public void Tests_PsHost_FailOnNonTerminatingError_ThrowsNonTerminatingErrorsAsRuntimeExceptions()
{
    PsHost<TestModule>
        .Create()
        .FailOnNonTerminatingError()
        .Execute("Invoke-NonTerminatingError");
}

Next we’ll see how to overcome the execution policies in the unit test context without altering the PowerShell environment policies.

No comments: