Test-driven development

Test-driven development plays a very important role in DevOps. The Wikipedia definition (https://en.wikipedia.org/wiki/Test-driven_development) of test-driven development is this:

"A software development process that relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, then the software is improved to pass the new tests, only."

By knowing your requirements so well that you can write test cases that accurately reflect those requirements, you automatically write fitting code. This is usually done by developing solid test cases first that test the so-called happy path. All code is then developed so that the test cases pass.

The benefit of this approach is that no unnecessary code is produced, since the code only needs to satisfy the requirements. TDD also leads to modularization of the code. This is something we do in PowerShell anyway and that should by now sound familiar; functions and cmdlets should only have one specific purpose, and fulfill that purpose well. Our code should already be modular.

There are also downsides to test-driven development. One of the main issues is that tests can be badly written or don't cover everything.

This can provide a false sense of security. Sure all Pester tests are green—but are the tests meaningful? Will they always be green? Another downside is that writing good tests is a time-consuming process, and can be seen as an overhead by people writing code:

# Testing your own functions
function New-ConfigDbEntry
{
param
(
$ServerInstance = 'localhostCMDB',

$Database = 'Devices',

[Parameter(Mandatory)]
$ComputerName
)

$query = "INSERT INTO {0} VALUES (N'{1}, {2:yyyyMMdd}'" -f $Database, $ComputerName, (Get-Date)

Invoke-SqlCmd -ServerInstance $ServerInstance -Database $Database -Query $query
}

# Unit tests to test your function as a black box
Describe 'Config DB module' {
function Invoke-SqlCmd {} # Empty function declaration if SqlServer module is not installed
Context 'New entry is added' {
$testParameters = @{
ServerInstance = 'somemachineCMDB'
Database = 'Devices'
}
$testObject = 'SomeMachineName'

# Mock external cmdlet with proper return value
Mock -CommandName Invoke-SqlCmd

It 'Should not throw' {
{New-ConfigDbEntry @testParameters -ComputerName $testObject} | Should -Not -Throw
}

It 'Should have called Invoke-SqlCmd once' {
Assert-MockCalled -CommandName Invoke-SqlCmd -Times 1 -Exactly
}
}
}

# Integration test to test if your function modified your infrastructure accordingly
Describe 'Config DB integration' {
Context 'New entry has been added' {
$instance = 'localhost estinstance'
$database = 'testdb'
$entry = 'SomeMachineName'

(Invoke-SqlCmd -ServerInstance $instance -Database $database -Query "SELECT ComputerName from $testdb").ComputerName | Should -Contain $entry
}
}

TDD is not only valuable for developers, but also for operations people. If you can define the requirements a service has of your infrastructure, you can write unit tests for your functions and integration tests for your infrastructure, defined in code like DSC configurations.

For community modules that help you with automated tests have a look at OVF: https://github.com/powershell/operation-validation-framework

By the way: If you are serious about SQL scripting with PowerShell, have a look at dbatools as well: https://dbatools.io

Especially with Desired State Configuration, integration tests are a must. If all DSC resources behave properly, the simplest test could be executing Get-DscConfiguration and Test-DscConfiguration to see whether all configured items have been applied properly. Only if all infrastructure integration tests have been passed do you want to deploy modified code into production.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset