mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Update testing guidelines (#2244)
* Move PesterDoAndDont.md into WritingPesterTests.md * Add powershell language moniker to codesnippets in WritingPesterTests.md Add extra new-lines for formatting * Adding here-string info to testings docs
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
## Do
|
||||
1. Name your files <descriptivetest>.tests.ps1
|
||||
2. Keep tests simple
|
||||
1. Test only what you need
|
||||
2. Reduce dependencies
|
||||
3. Be sure to tag your `Describe` blocks based on their purpose
|
||||
1. Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second.
|
||||
2. Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality
|
||||
3. Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests.
|
||||
4. Make sure that `Describe`/`Context`/`It` descriptions are useful
|
||||
1. The error message should not be the place where you describe the test
|
||||
5. Use `Context` to group tests
|
||||
1. Multiple `Context` blocks can help you group your test suite into logical sections
|
||||
6. Use `BeforeAll`/`AfterAll`/`BeforeEach`/`AfterEach` instead of custom initiators
|
||||
7. Prefer Try-Catch for expected errors and check $_.fullyQualifiedErrorId (don't use `should throw`)
|
||||
8. Use `-testcases` when iterating over multiple `It` blocks
|
||||
9. Use code coverage functionality where appropriate
|
||||
10. Use `Mock` functionality when you don't have your entire environment
|
||||
11. Avoid free code in a `Describe` block
|
||||
1. Use `[Before|After][Each|All]` see [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block)
|
||||
12. Avoid creating or using test files outside of TESTDRIVE:
|
||||
1. TESTDRIVE: has automatic clean-up
|
||||
13. Keep in mind that we are creating cross platform tests
|
||||
1. Avoid using the registry
|
||||
2. Avoid using COM
|
||||
14. Avoid being too specific about the _count_ of a resource as these can change platform to platform
|
||||
1. ex: checking for the count of loaded format files, check rather for format data for a specific type
|
||||
|
||||
## Don't
|
||||
1. Don't have too many evaluations in a single It block
|
||||
1. The first `Should` failure will stop that block
|
||||
2. Don't use `Should` outside of an `It` Block
|
||||
3. Don't use the word "Error" or "Fail" to test a positive case
|
||||
1. ex: "Get-Childitem TESTDRIVE: shouldn't fail", rather "Get-ChildItem should be able to retrieve file listing from TESTDRIVE"
|
||||
@@ -12,7 +12,7 @@ When creating tests, keep the following in mind:
|
||||
Examples:
|
||||
Here's the simplest of tests
|
||||
|
||||
```
|
||||
```powershell
|
||||
Describe "A variable can be assigned and retrieved" {
|
||||
It "Create a variable and make sure it's value is correct" {
|
||||
$a = 1
|
||||
@@ -23,7 +23,7 @@ Describe "A variable can be assigned and retrieved" {
|
||||
|
||||
If you need to do type checking, that can be done as well
|
||||
|
||||
```
|
||||
```powershell
|
||||
Describe "One is really one" {
|
||||
It "Compare 1 to 1" {
|
||||
$a = 1
|
||||
@@ -35,8 +35,10 @@ Describe "One is really one" {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
alternatively, you could do the following:
|
||||
```
|
||||
|
||||
```powershell
|
||||
Describe "One is really one" {
|
||||
It "Compare 1 to 1" {
|
||||
$a = 1
|
||||
@@ -50,7 +52,8 @@ Describe "One is really one" {
|
||||
```
|
||||
|
||||
If you are checking for proper errors, do that in a `try/catch`, and then check `FullyQualifiedErrorId`. Checking against `FullyQualifiedErrorId` is recommended because it does not change based on culture as an error message might.
|
||||
```
|
||||
|
||||
```powershell
|
||||
...
|
||||
it "Get-Item on a nonexisting file should have error PathNotFound" {
|
||||
try
|
||||
@@ -87,7 +90,7 @@ A test may need to work with file operations and validate certain types of file
|
||||
|
||||
The following example illustrates the feature:
|
||||
|
||||
```
|
||||
```powershell
|
||||
function Add-Footer($path, $footer) {
|
||||
Add-Content $path -Value $footer
|
||||
}
|
||||
@@ -107,8 +110,8 @@ Describe "Add-Footer" {
|
||||
When this test completes, the contents of the TestDrive PSDrive will be removed.
|
||||
|
||||
#### Parameter Generation
|
||||
```
|
||||
|
||||
```powershell
|
||||
$testCases = @(
|
||||
@{ a = 0; b = 1; ExpectedResult = 1 }
|
||||
@{ a = 1; b = 0; ExpectedResult = 1 }
|
||||
@@ -129,7 +132,8 @@ You can also construct loops and pass values as parameters, including the expect
|
||||
#### Mocking
|
||||
Mocks the behavior of an existing command with an alternate implementation. This creates new behavior for any existing command within the scope of a Describe or Context block. The function allows you to specify a script block that will become the command's new behavior.
|
||||
The following example illustrates simple use:
|
||||
```
|
||||
|
||||
```powershell
|
||||
Context "Get-Random is not random" {
|
||||
Mock Get-Random { return 3 }
|
||||
It "Get-Random returns 3" {
|
||||
@@ -137,10 +141,12 @@ Context "Get-Random is not random" {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
More information may be found on the [wiki](https://github.com/pester/Pester/wiki/Mock)
|
||||
### Free Code in a Describe block
|
||||
Code execution in Pester can be very subtle and can cause issues when executing test code. The execution of code which lays outside of the usual code blocks may not happen as you expect. Consider the following:
|
||||
```
|
||||
|
||||
```powershell
|
||||
Describe it {
|
||||
Write-Host -For DarkRed "Before Context"
|
||||
Context "subsection" {
|
||||
@@ -197,5 +203,86 @@ Passed: 1 Failed: 0 Skipped: 0 Pending: 0
|
||||
The DESCRIBE BeforeAll block is executed before any other code even though it was at the bottom of the Describe block, so if state is set elsewhere in the describe BLOCK, that state will not be visible (as the code will not yet been run). Notice, too, that the BEFOREALL block in Context is executed before any other code in that block.
|
||||
Generally, you should have code reside in one of the code block elements of `[Before|After][All|Each]`, especially if those block rely on state set by free code elsewhere in the block.
|
||||
|
||||
#### Multi-line strings
|
||||
|
||||
You may want to have a test like
|
||||
|
||||
```powershell
|
||||
It 'tests multi-line string' {
|
||||
Get-MultiLineString | Should Be @'
|
||||
first line
|
||||
second line
|
||||
'@
|
||||
}
|
||||
```
|
||||
|
||||
There are problems with using here-strings with verifying the output results.
|
||||
The reason for it are line-ends.
|
||||
|
||||
They cause problems for two reasons:
|
||||
|
||||
* They are different on different platforms (`\r\n` on windows and `\n` on unix).
|
||||
* Even on the same system, they depends on the way how the repo was cloned.
|
||||
|
||||
Particularly, in the default AppVeyour CI windows image, you will get `\n` line ends in all your files.
|
||||
That causes problems, because at runtime `Get-MultiLineString` would likely produce `\r\n` line ends on windows.
|
||||
|
||||
Some workaround could be added, but they are sub-optimal and make reading test code harder.
|
||||
|
||||
```powershell
|
||||
function normalizeEnds([string]$text)
|
||||
{
|
||||
$text -replace "`r`n?|`n", "`r`n"
|
||||
}
|
||||
|
||||
It 'tests multi-line string' {
|
||||
normalizeEnds (Get-MultiLineString) | Should Be (normalizeEnds @'
|
||||
first line
|
||||
second line
|
||||
'@)
|
||||
}
|
||||
```
|
||||
|
||||
When appropriate, you can avoid creating multi-line strings at the first place.
|
||||
These commands create an array of strings:
|
||||
|
||||
* `Get-Content`
|
||||
* `Out-String -Stream`
|
||||
|
||||
Pester Do and Don't
|
||||
===================
|
||||
|
||||
## Do
|
||||
1. Name your files <descriptivetest>.tests.ps1
|
||||
2. Keep tests simple
|
||||
1. Test only what you need
|
||||
2. Reduce dependencies
|
||||
3. Be sure to tag your `Describe` blocks based on their purpose
|
||||
1. Tag `CI` indicates that it will be run as part of the continuous integration process. These should be unit test like, and generally take less than a second.
|
||||
2. Tag `Feature` indicates a higher level feature test (we will run these on a regular basis), for example, tests which go to remote resources, or test broader functionality
|
||||
3. Tag `Scenario` indicates tests of integration with other features (these will be run on a less regular basis and test even broader functionality than feature tests.
|
||||
4. Make sure that `Describe`/`Context`/`It` descriptions are useful
|
||||
1. The error message should not be the place where you describe the test
|
||||
5. Use `Context` to group tests
|
||||
1. Multiple `Context` blocks can help you group your test suite into logical sections
|
||||
6. Use `BeforeAll`/`AfterAll`/`BeforeEach`/`AfterEach` instead of custom initiators
|
||||
7. Prefer Try-Catch for expected errors and check $_.fullyQualifiedErrorId (don't use `should throw`)
|
||||
8. Use `-testcases` when iterating over multiple `It` blocks
|
||||
9. Use code coverage functionality where appropriate
|
||||
10. Use `Mock` functionality when you don't have your entire environment
|
||||
11. Avoid free code in a `Describe` block
|
||||
1. Use `[Before|After][Each|All]` see [Free Code in a Describe block](WritingPesterTests.md#free-code-in-a-describe-block)
|
||||
12. Avoid creating or using test files outside of TESTDRIVE:
|
||||
1. TESTDRIVE: has automatic clean-up
|
||||
13. Keep in mind that we are creating cross platform tests
|
||||
1. Avoid using the registry
|
||||
2. Avoid using COM
|
||||
14. Avoid being too specific about the _count_ of a resource as these can change platform to platform
|
||||
1. ex: checking for the count of loaded format files, check rather for format data for a specific type
|
||||
|
||||
## Don't
|
||||
1. Don't have too many evaluations in a single It block
|
||||
1. The first `Should` failure will stop that block
|
||||
2. Don't use `Should` outside of an `It` Block
|
||||
3. Don't use the word "Error" or "Fail" to test a positive case
|
||||
1. ex: "Get-Childitem TESTDRIVE: shouldn't fail", rather "Get-ChildItem should be able to retrieve file listing from TESTDRIVE"
|
||||
|
||||
Reference in New Issue
Block a user