Metrics collected by PSCodeHealth
Metrics collected for each function
LinesOfCode
It measures the number of lines of code in the specified function definition.
The single line comments, multiple lines comments and comment-based help are not executable code, so they are not counted.
Lower is better, because lenghty functions tend to be difficult to read and maintain.
Default thresholds : (Source)
The thresholds are 50% higher than the recommendations in the above article because PowerShell advanced functions tend have more boilerplate code than C# methods (mainly due to the various parameter attributes being more widely used in PowerShell, for validation purposes, pipeline input, etc...).
- Warning : greater than 30
- Fail : greater than 60
ScriptAnalyzerFindings
It counts the total number of best practice violations found by PSScriptAnalyzer in the specified function definition, regardless of their severity.
PSScriptAnalyzer is a static code checker for PowerShell. It checks readability, quality and security best practices in PowerShell code by running a set of rules. The rules are based on PowerShell best practices identified by PowerShell Team and the community.
PSCodeHealth uses the default PSScriptAnalyzer rules.
Lower is better, because high numbers of PSScriptAnlyzer findings generally reflects low code quality, maintainability or safety.
Default thresholds :
- Warning : greater than 7
- Fail : greater than 12
ContainsHelp
Tells whether or not the specified function definition contains comment-based help. Possible values are : True or False.
It is an important best practice to have help information for each function, even private function (for contributors, or code reviewers).
At the very least, it should have a short statement describing the function's purpose. That is the Synopsis.
TestCoverage
It measures the percentage of lines of code in the specified function definition that are exercised (executed) during a suite of tests.
Note : the code executed during tests cannot always be considered as tested. It is only tested if it is executed and there is one or more test(s) specifically designed to validate that the code behaves as expected.
Higher is better. Good tests provide confidence that the code behaves as expected. How confident depends mostly on the percentage of code which is covered by the tests. This is why code coverage of the tests is an important metric. It is an indicator of how thoroughly the different possible code paths and edge cases are tested.
Default thresholds : (Source)
- Warning : less than 80
- Fail : less than 70
CommandsMissed
The number of commands in the specified function which are not exercized by the tests.
This is the number of commands, not lines, because the code coverage feature of Pester uses breakpoints, which can only be triggered by commands (Source).
Lower is better. Any command not exercized by tests is untested, which means any defect it may contain will not be detected. Or at best, it will only be detected at later stages of the code lifecycle (user acceptance testing, QA, or in production).
The later a defect is detected, the more expensive (in time and money) it is to fix.
Default thresholds :
- Warning : greater than 6
- Fail : greater than 12
Complexity
This is the cyclomatic complexity of a given function. Cyclomatic complexity measures the number of possible execution paths through a given section of code. This is intended to evaluate code complexity.
Lower is better, because complex code tends to have the following properties :
- Difficult to read/understand
- Difficult to test
- More prone to defects
- Make defects more difficult to identify
- More difficult and risky to change/refactor/maintain
Default thresholds : (Source)
- Warning : greater than 15
- Fail : greater than 30
For more details on how the cyclomatic complexity is calculated, please refer to this article.
MaximumNestingDepth
This is the depth of the most deeply nested code in a given piece of code (a function, here). This measures a different aspect of complexity from the "cyclomatic complexity", so these 2 metrics are complementary. The nesting depth of a piece of code is an indication of the complexity of its context.
Again, lower is better.
Default thresholds : (Source)
- Warning : greater than 4
- Fail : greater than 8
For more details on how the maximum nesting depth is calculated, please refer to this article.
Metrics collected for the overall health report
These are the overall metrics for all PowerShell code in the files or folder specified via the Path parameter.
Files
The number of PowerShell files. These are files with an extension like : '*.ps*1'.
Test scripts are excluded, as are '*.ps1xml' files because these don't contain any code.
Functions
The overall number of function definitions found.
LinesOfCodeTotal
The total number of lines of code across all files and functions.
Default thresholds :
- Warning : greater than 1000
- Fail : greater than 2000
LinesOfCodeAverage
The average number of lines of code per function.
Default thresholds : (Source)
The thresholds are 50% higher than the recommendations in the above article because PowerShell advanced functions tend have more boilerplate code than C# methods (mainly due to the various parameter attributes being more widely used in PowerShell, for validation purposes, pipeline input, etc...).
- Warning : greater than 30
- Fail : greater than 60
ScriptAnalyzerFindingsTotal
The total number of best practice violations found by PSScriptAnalyzer across all files.
Default thresholds :
- Warning : greater than 30
- Fail : greater than 60
ScriptAnalyzerErrors
The total number of best practice violations of 'Error' severity found by PSScriptAnalyzer across all files.
Default thresholds :
- Warning : greater than 1
- Fail : greater than 3
ScriptAnalyzerWarnings
The total number of best practice violations of 'Warning' severity found by PSScriptAnalyzer across all files.
Default thresholds :
- Warning : greater than 10
- Fail : greater than 20
ScriptAnalyzerInformation
The total number of best practice violations of 'Information' severity found by PSScriptAnalyzer across all files.
Default thresholds :
- Warning : greater than 20
- Fail : greater than 40
ScriptAnalyzerFindingsAverage
The average number of best practice violations found by PSScriptAnalyzer per function.
Default thresholds :
- Warning : greater than 7
- Fail : greater than 12
FunctionsWithoutHelp
The total number of the function which do not contain any comment-based help.
It is an important best practice to have help information for each function, even private function (for contributors, or code reviewers).
At the very least, it should have a short statement describing the function's purpose. That is the Synopsis.
There is no compliance rule for this metric because it is highly dependent on the total number of functions, and arguably, on the number of public functions.
NumberOfTests
The total number of tests found by Pester.
Keep in mind that this metric is purely quantitative : it does not indicate anything about the quality or the coverage of the tests. This is why there is no compliance rule associated with this metric.
NumberOfFailedTests
The total number of failed tests. This is using Invoke-Pester
with the Strict
parameter, this means that any test marked as skipped, pending, or inconclusive is considered as failed.
Lower is better, 0 is highly recommended because any failing test indicates that the code doesn't behave as intended (or at least, as intended when the test(s) were written).
This means there is most likely a defect either in the code or in the test(s). This type of problems should be prioritized over any other type of code quality issues.
Default thresholds :
- Warning : greater than 1
- Fail : greater than 3
NumberOfPassedTests
The total number of passed tests.
This metric is purely quantitative and highly dependent on the total number of tests : it does not indicate anything about the quality, effectiveness or coverage of the tests. This is why there is no compliance rule associated with this metric.
TestsPassRate
The overall percentage of passing tests.
The higher the better, because it gives an indication of the quality of the code being tested. More specifically, it answers the question : "To which extent the code behaves as intended ?", assuming the intent is properly reflected in the tests.
Default thresholds :
- Warning : less than 99
- Fail : less than 97
TestCoverage
The overall percentage of code which is exercised across all PowerShell files by the tests.
Note : the code executed during tests cannot always be considered as tested. It is only tested if it is executed and there is one or more test(s) specifically designed to validate that the code behaves as expected.
Higher is better. Good tests provide confidence that the code behaves as expected. How confident depends mostly on the percentage of code which is covered by the tests. This is why code coverage of the tests is an important metric. It is an indicator of how thoroughly the different possible code paths and edge cases are tested.
Default thresholds : (Source)
- Warning : less than 80
- Fail : less than 70
CommandsMissedTotal
The total number of commands which are not exercized by the tests.
This is the number of commands, not lines, because the code coverage feature of Pester uses breakpoints, which can only be triggered by commands (Source).
Lower is better. Any command not exercized by tests is untested, which means any defect it may contain will not be detected. Or at best, it will only be detected at later stages of the code lifecycle (user acceptance testing, QA, or in production).
The later a defect is detected, the more expensive (in time and money) it is to fix.
Default thresholds :
- Warning : greater than 200
- Fail : greater than 400
ComplexityAverage
This is the average cyclomatic complexity per function. Cyclomatic complexity measures the number of possible execution paths through a given section of code. This is intended to evaluate code complexity.
Lower is better, because complex code tends to have the following properties :
- Difficult to read/understand
- Difficult to test
- More prone to defects
- Make defects more difficult to identify
- More difficult and risky to change/refactor/maintain
Default thresholds : (Source)
- Warning : greater than 15
- Fail : greater than 30
For more details on how the cyclomatic complexity is calculated, please refer to this article.
ComplexityHighest
This is the cyclomatic complexity of the function which has the highest complexity value in the health report. Cyclomatic complexity measures the number of possible execution paths through a given section of code. This is intended to evaluate code complexity.
Lower is better, because complex code tends to have the following properties :
- Difficult to read/understand
- Difficult to test
- More prone to defects
- Make defects more difficult to identify
- More difficult and risky to change/refactor/maintain
Default thresholds : the double of the average (Source)
- Warning : greater than 30
- Fail : greater than 60
NestingDepthAverage
This is the average of MaximumNestingDepth per function.
MaximumNestingDepth is the depth of the most deeply nested code in a given function. This measures a different aspect of complexity from the "cyclomatic complexity", so these 2 metrics are complementary. The nesting depth of a piece of code is an indication of the complexity of its context.
Again, lower is better.
Default thresholds : (Source)
- Warning : greater than 4
- Fail : greater than 8
For more details on how the maximum nesting depth is calculated, please refer to this article.
NestingDepthHighest
This is the MaximumNestingDepth of the function which has the highest value in the health report.
MaximumNestingDepth is the depth of the most deeply nested code in a given function. This measures a different aspect of complexity from the "cyclomatic complexity", so these 2 metrics are complementary. The nesting depth of a piece of code is an indication of the complexity of its context.
Again, lower is better.
Default thresholds : the double of the average (Source)
- Warning : greater than 8
- Fail : greater than 16