Pester: Generating Command Interface Tests

I’ve for long thought Interface Testing was the most repetitive yet critical task to let a Module or commands evolve without breaking backward compatibility, and upsetting those who depends on it.

While Unit Testing ensures the code behaves as expected and meets its design and requirements, Interface Testing for commands or functions focuses on the contracts it offers to its consumer. It ensures the contracts (the command prototype or syntax) are consistent over time.

InterfaceTestGenerator.gif

PowerShell being Metadata-driven, it is easy to get command information via Get-Command, and the returned object of type CmdletInfo, FunctionInfo or so on, gives the details of Parameters for each parameter set, or the command list of OutputTypes.

#List of Parameter Sets Name:
(Get-Command Get-Process).ParameterSets.Name

#List of Parameter name for the first ParameterSet
(Get-command Get-Process).ParameterSets[0].Parameters.Name

From those it’s trivial to consistently generate some code to test your Interfaces, in the form you’d like, and here’s an example, with a drawback I’ll explain shortly:

One way to use the script above:

. .\TestGenerator.ps1
Get-Command Get-Process | Export-StructuralUnitTestFromCommand | `
 Out-File ./Get-Process.tests.ps1 -Force -Encoding utf8
Invoke-Pester .\Get-Process.tests.ps1

The goal of Interface testing, is to ensure backward compatibility of your publicly exposed functions (API, as in Application  Programming Interface). You want a module to offer functionalities in the same way, independently of the evolution of the inner (private) code.

If you follow SemVer for your versioning, when you add functionality to your module and as long as the API is compatible (the test generate as above should pass), you do not increase the Major version: i.e. from 2.1.3345 to 2.2.2138

If you have to make a breaking change (and you have considered creating a new parameter set or a proxy/stub function that provides the same interface that was previously available), then you indicate the breaking change by increasing its Major version: i.e. from 2.2.2138 to 3.0.0

This means that for each release, you should generate the Interface tests, and make sure it runs against the previous release’s ones, and version accordingly.

The main flaw of the sample generator I’ve given above, is that it includes specific Parameter Sets, and name them, although I believe those should be considered internal to the command…

I will revisit this at some point, or feel free to submit a PR!

Advertisements