2

I've recently started using Pester to write tests in PowerShell and I've got no problem running basic tests, however I'm looking to build some more complex tests and I'm struggling on what to do with variables that I need for the tests.

I'm writing tests to validate some cloud infrastructure, so after we've run a deployment it goes through and validates that it has deployed correctly and everything is where it should be. Because of this there are a large number of variables needed, VM Names, network names, subnet configurations etc. that we want to validate.

In normal PowerShell scripts these would be stored outside the script and fed in as parameters, but this doesn't seem to fit with the design of Pester or BDD, should I be hard coding these variables inside my tests? This doesn't seem very intuitive, especially if I might want to re-use these tests for other environments. I did experiment with storing them in an external JSON file and reading that into my test, but even then I need to hardcode the path to the JSON file in my script. Or am I doing it all wrong and there is a better approach?

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68
Sam Cogan
  • 4,124
  • 7
  • 44
  • 76

2 Answers2

4

I don't know if I can speak to best practice for this sort of thing but at the end of the day a Pester script is just a Powershell script so there's no harm in doing powershell anywhere in and around your tests (although beware that some constructs have their own scopes).

I would probably use a param block at the top of the script and pass in variables via the -script parameter of invoke-pester per this suggestion: http://wahlnetwork.com/2016/07/28/using-the-script-param-to-pass-parameters-into-pester-tests/

At the end of the day "best practice" for pester testing (particularly for infrastructure validation) is very loosely defined/pretty nonexistent.

As an example, I used a param block in my Active Directory test script that (in part) tests against a stored configuration file much as you described:

https://github.com/markwragg/Test-ActiveDirectory/blob/master/ActiveDirectory.tests.ps1

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68
  • 1
    Thanks, that example is really helpful. I'm at least not going in completely the wrong direction. – Sam Cogan Mar 23 '17 at 18:16
  • 2
    I agree. I would just like to point out that even though there is no best practice, it is best to keep stuff simple. In the OVF world, logic and the tests is often mixed. I would suggest to build a set of functions that allow you to do the dynamic stuff (like loading config.json) and test those functions using strict testing practices. And then you can take those functions and build a >validation< suite from them. That suite will still use Pester as it's runner, but it won't be tests. Tests test your code, Your code composes into validation suite. Suite validates multiple environments. – nohwnd Mar 23 '17 at 20:38
  • @SamCogan FYI I tweeted this question to the pester team on twitter and the above reply is from them. – Mark Wragg Mar 23 '17 at 21:14
  • 1
    @nohwnd OK, thanks, so my validation suite is still using Pester syntax and so on, there's nothing special about validation over tests, other than the fact I'm not testing code right? – Sam Cogan Mar 23 '17 at 21:21
  • 1
    Yes there is nothing special about validations, except that they do not follow the rules that are usually followed in tests. You can also take the opportunity and write a set of functions that will fit your task better than the generic Pester language. (You need to keep the Describe, Context but you can have your own assertions that use language specific to your task: Assert-ServiceRunning abc vs. Get-Service abc | select -expand status | should be 'running' etc.). Or it "validates somethnig" On-NanoServer { ... test for nano server.. } On-FullWindows { ...test for windows ...}. and so on. – nohwnd Mar 24 '17 at 10:04
0

As described here, you can add BeforeAll block to define the variables

Describe "Check name" {
  BeforeAll {
    $name = "foo"
  }
  It "should have the correct value" {
    $name | Should -Be "foo"
  }
}
Musa Biralo
  • 479
  • 1
  • 5
  • 16