PageSourceSearch

https://pester.dev/assets/js/89be631f.fa41c9c0.js

js pester.dev collected 2026-10-03 19:39:40 UTC 42,644 bytes, 1 lines download raw bytes

1"use strict";(self.webpackChunkpester_docs=self.webpackChunkpester_docs||[]).push([["5742"],{8992(e,n,t){t.r(n),t.d(n,{metadata:()=>s,default:()=>u,frontMatter:()=>o,contentTitle:()=>d,toc:()=>h,assets:()=>c});var s=JSON.parse('{"id":"usage/data-driven-tests","title":"Data driven tests","description":"Pester can generate tests based on data. This can range from providing multiple examples on a single `It`, to generating whole set of tests based on an external configuration file","source":"@site/versioned_docs/version-v5/usage/data-driven-tests.mdx","sourceDirName":"usage","slug":"/usage/data-driven-tests","permalink":"/docs/v5/usage/data-driven-tests","draft":false,"unlisted":false,"editUrl":"https://github.com/pester/docs/edit/main/versioned_docs/version-v5/usage/data-driven-tests.mdx","tags":[],"version":"v5","frontMatter":{"title":"Data driven tests","description":"Pester can generate tests based on data. This can range from providing multiple examples on a single `It`, to generating whole set of tests based on an external configuration file"},"sidebar":"docs","previous":{"title":"Discovery and Run","permalink":"/docs/v5/usage/discovery-and-run"},"next":{"title":"Setup and teardown","permalink":"/docs/v5/usage/setup-and-teardown"}}'),i=t(1987),l=t(7008);function r(e){let n={code:"code",p:"p",pre:"pre",...(0,l.R)(),...e.components},{Details:t}=n;return t||function(e,n){throw Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,i.jsxs)(t,{children:[(0,i.jsx)("summary",{children:"Required code for samples (PowerShell 6 or later)"}),(0,i.jsxs)("div",{children:[(0,i.jsx)(n.p,{children:"This module is required for the Emoji and Fruit tests below. Copy and paste this in your console before running the tests."}),(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"Get-Module PesterDemoFunctions | Remove-Module\nNew-Module PesterDemoFunctions -ScriptBlock {\n    $emojis = @(\n        @{ Name = 'apple'; Symbol = '\u{1F34E}'; Kind = 'Fruit' }\n        @{ Name = 'beaming face with smiling eyes'; Symbol = '\u{1F601}'; Kind = 'Face' }\n        @{ Name = 'cactus'; Symbol = '\u{1F335}'; Kind = 'Plant' }\n        @{ Name = 'giraffe'; Symbol = '\u{1F992}'; Kind = 'Animal' }\n        @{ Name = 'pencil'; Symbol = '\u270F\uFE0F'; Kind = 'Item' }\n        @{ Name = 'penguin'; Symbol = '\u{1F427}'; Kind = 'Animal' }\n        @{ Name = 'pensive'; Symbol = '\u{1F614}'; Kind = 'Face' }\n        @{ Name = 'slightly smiling face'; Symbol = '\u{1F642}'; Kind = 'Face' }\n        @{ Name = 'smiling face with smiling eyes'; Symbol = '\u{1F60A}'; Kind = 'Face' }\n    ) | ForEach-Object { [PSCustomObject]$_ }\n\n    function Get-Emoji ([string]$Name = '*') {\n        $script:emojis | Where-Object Name -like $Name | ForEach-Object Symbol\n    }\n\n    function Get-EmojiKind {\n        param(\n            [Parameter(Mandatory = $true, ValueFromPipeline = $true)]\n            [string]$Emoji\n        )\n        process {\n            $script:emojis | Where-Object Symbol -eq $Emoji | Foreach-Object Kind\n        }\n    }\n\n    $fruitBasket = [System.Collections.ArrayList]@('\u{1F34E}','\u{1F34C}','\u{1F95D}','\u{1F951}','\u{1F347}','\u{1F350}')\n\n    function Get-FruitBasket {\n        $script:fruitBasket\n    }\n\n    function Remove-FruitBasket {\n        param(\n            [Parameter(Mandatory = $true)]\n            [string]$Item\n        )\n        $script:fruitBasket.Remove($Item)\n    }\n\n    function Reset-FruitBasket {\n        $script:fruitBasket = [System.Collections.ArrayList]@('\u{1F34E}','\u{1F34C}','\u{1F95D}','\u{1F951}','\u{1F347}','\u{1F350}')\n    }\n} | Import-Module\n"})})]})]})}function a(e={}){let{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(r,{...e})}):r(e)}let o={title:"Data driven tests",description:"Pester can generate tests based on data. This can range from providing multiple examples on a single `It`, to generating whole set of tests based on an external configuration file"},d,c={},h=[{value:"Using <code>-ForEach</code> &amp; <code>-TestCases</code> with hashtable",id:"using--foreach---testcases-with-hashtable",level:2},{value:"<code>-ForEach</code> on <code>Describe</code> and <code>Context</code>
1",id:"-foreach-on-describe-and-context",level:4},{value:"Choosing a subset of data",id:"choosing-a-subset-of-data",level:4},{value:"Using <code>-ForEach</code> &amp; <code>-TestCases</code> with an array",id:"using--foreach---testcases-with-an-array",level:2},{value:"Using <code>&lt;&gt;</code> templates",id:"using--templates",level:2},{value:"<code>&lt;_&gt;</code> in template",id:"_-in-template",level:4},{value:"Using dot-navigation in <code>&lt;&gt;</code> template",id:"using-dot-navigation-in--template",level:3},{value:"Escaping",id:"escaping",level:3},{value:"Internals",id:"internals",level:4},{value:"Providing external data to tests",id:"providing-external-data-to-tests",level:2},{value:"Re-using the same test file",id:"re-using-the-same-test-file",level:4},{value:"Re-using the same data set",id:"re-using-the-same-data-set",level:4},{value:"Wildcards",id:"wildcards",level:4},{value:"<code>BeforeDiscovery</code>",id:"beforediscovery",level:2},{value:"Migrating from Pester v4",id:"migrating-from-pester-v4",level:2},{value:"Execution is not top down",id:"execution-is-not-top-down",level:3},{value:"Variables defined during <code>Discovery</code> are not available in <code>Run</code>",id:"variables-defined-during-discovery-are-not-available-in-run",level:3},{value:"Moving away from <code>foreach</code>",id:"moving-away-from-foreach",level:3},{value:"Another variation on <code>foreach</code>",id:"another-variation-on-foreach",level:3}];function x(e){let n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h2:"h2",h3:"h3",h4:"h4",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,l.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["Migrating from Pester v4? Jump to ",(0,i.jsx)(n.a,{href:"#migrating-from-pester-v4",children:"Migrating from Pester v4"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Pester can generate tests based on data. This can range from providing multiple examples on a single ",(0,i.jsx)(n.code,{children:"It"}),", to generating whole set of tests based on an external configuration file."]}),"\n",(0,i.jsxs)(n.h2,{id:"using--foreach---testcases-with-hashtable",children:["Using ",(0,i.jsx)(n.code,{children:"-ForEach"})," & ",(0,i.jsx)(n.code,{children:"-TestCases"})," with hashtable"]}),"\n",(0,i.jsxs)(n.p,{children:["The most common usage of data driven tests is providing multiple examples to a single ",(0,i.jsx)(n.code,{children:"It"}),". This way we reuse the body of the test. And decorate the test with examples of its usage. This is superior to copy-pasting tests for each example, because the amount of code to maintain is reduced, the amount of typos is reduced, and it is very easy to add more examples."]}),"\n",(0,i.jsxs)(n.p,{children:["To define examples for a test, use ",(0,i.jsx)(n.code,{children:"-ForEach"})," on an ",(0,i.jsx)(n.code,{children:"It"})," block. On ",(0,i.jsx)(n.code,{children:"It"})," block the parameter is also aliased ",(0,i.jsx)(n.code,{children:"-TestCases"})," for backwards compatibility."]}),"\n",(0,i.jsx)(n.p,{children:"The data are provided as an array of hashtables:"}),"\n","\n",(0,i.jsx)(a,{}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji" {\n    It "Returns <expected> (<name>)" -ForEach @(\n        @{ Name = "cactus"; Expected = \'\u{1F335}\'}\n        @{ Name = "giraffe"; Expected = \'\u{1F992}\'}
1\n    ) {\n        Get-Emoji -Name $name | Should -Be $expected\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"@()"})," is an array. One test will be generated for each item in the array."]}),"\n",(0,i.jsxs)(n.p,{children:["Inside of the ",(0,i.jsx)(n.code,{children:"@()"})," array, a hashtable is provided ",(0,i.jsx)(n.code,{children:"@{}"}),". This hashtable can have multiple keys, here it is ",(0,i.jsx)(n.code,{children:"Name"})," and ",(0,i.jsx)(n.code,{children:"Expected"}),", and each one of those keys will be defined as a variable in the test. These variables can be used in the test, and also in the ",(0,i.jsx)(n.code,{children:"<>"})," templates, described below."]}),"\n",(0,i.jsx)(n.p,{children:"The code above will generate tests that are equivalent to this:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji" {\n    It "Returns \u{1F335} (cactus)" {\n        Get-Emoji -Name cactus | Should -Be \'\u{1F335}\'\n    }\n\n    It "Returns \u{1F992} (giraffe)" {\n        Get-Emoji -Name giraffe | Should -Be \'\u{1F992}\'\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["Using ",(0,i.jsx)(n.code,{children:"-ForEach"})," (or ",(0,i.jsx)(n.code,{children:"-TestCases"}),") we can now very easily provide more examples just by adding more data:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji" {\n    It "Returns <expected> (<name>)" -ForEach @(\n        @{ Name = "cactus"; Expected = \'\u{1F335}\'}\n        @{ Name = "giraffe"; Expected = \'\u{1F992}\'}\n        @{ Name = "apple"; Expected = \'\u{1F34E}\'}\n        @{ Name = "pencil"; Expected = \'\u270F\uFE0F\'}\n        @{ Name = "penguin"; Expected = \'\u{1F427}\'}\n        @{ Name = "smiling face with smiling eyes"; Expected = \'\u{1F60A}\'}
1\n    ) {\n        Get-Emoji -Name $name | Should -Be $expected\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.h4,{id:"-foreach-on-describe-and-context",children:[(0,i.jsx)(n.code,{children:"-ForEach"})," on ",(0,i.jsx)(n.code,{children:"Describe"})," and ",(0,i.jsx)(n.code,{children:"Context"})]}),"\n",(0,i.jsxs)(n.p,{children:["The same ",(0,i.jsx)(n.code,{children:"-ForEach"})," syntax is used on ",(0,i.jsx)(n.code,{children:"Describe"})," (or ",(0,i.jsx)(n.code,{children:"Context"}),") to generate those blocks from the provided data:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji <name>" -ForEach @(\n    @{ Name = "cactus"; Symbol = \'\u{1F335}\'; Kind = \'Plant\' }\n    @{ Name = "giraffe"; Symbol = \'\u{1F992}\'; Kind = \'Animal\' }\n) {\n    It "Returns <symbol>"  {\n        Get-Emoji -Name $name | Should -Be $symbol\n    }\n\n    It "Has kind <kind>" {\n        Get-Emoji -Name $name | Get-EmojiKind | Should -Be $kind\n    }\n}\n'})}),"\n",(0,i.jsx)(n.p,{children:"Which is equivalent to writing:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji cactus" {\n    It "Returns \u{1F335}" {\n        Get-Emoji -Name cactus | Should -Be \'\u{1F335}\'\n    }\n\n    It "Has kind Plant" {\n        Get-Emoji -Name cactus | Get-EmojiKind | Should -Be \'Plant\'\n    }\n}\n\nDescribe "Get-Emoji giraffe" {\n    It "Returns \u{1F992}" {\n        Get-Emoji -Name giraffe | Should -Be \'\u{1F992}\'\n    }\n\n    It "Has kind Animal" {\n        Get-Emoji -Name giraffe | Get-EmojiKind | Should -Be \'Animal\'\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h4,{id:"choosing-a-subset-of-data",children:"Choosing a subset of data"}),"\n",(0,i.jsxs)(n.p,{children:["The provided data will be available in both ",(0,i.jsx)(n.code,{children:"Discovery"})," and ",(0,i.jsx)(n.code,{children:"Run"}),", which allows us to generate tests based on the current data. Here for example we generate tests in a ",(0,i.jsx)(n.code,{children:"Context"}),", based on the data provided to the ",(0,i.jsx)(n.code,{children:"Describe"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Get-Emoji <name>" -ForEach @(\n    @{\n        Name = "cactus";\n        Symbol = \'\u{1F335}\';\n        Kind = \'Plant\'\n        Runes = @(\n            @{ Index = 0; Rune = 127797 }\n        )\n    }\n    @{\n        Name = "pencil"\n        Symbol = \'\u270F\uFE0F\'\n        Kind = \'Item\'\n        Runes = @(\n            @{ Index = 0; Rune = 9999 }\n            @{ Index = 1; Rune = 65039 }\n        )\n    }\n) {\n    It "Returns <symbol>
1"  {\n        Get-Emoji -Name $name | Should -Be $symbol\n    }\n\n    It "Has kind <kind>" {\n        Get-Emoji -Name $name | Get-EmojiKind | Should -Be $kind\n    }\n\n    Context "Runes (each character in multibyte emoji)" -ForEach $runes {\n        It "Has rune <rune> on index <index>" {\n            $actual = @((Get-Emoji -Name $name).EnumerateRunes())\n            $actual[$index].Value | Should -Be $rune\n        }\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.h2,{id:"using--foreach---testcases-with-an-array",children:["Using ",(0,i.jsx)(n.code,{children:"-ForEach"})," & ",(0,i.jsx)(n.code,{children:"-TestCases"})," with an array"]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"-ForEach"})," is most powerful when used with an array of hashtables, but it can take any array. In that case it will define ",(0,i.jsx)(n.code,{children:"$_"})," variable, representing the current item. This approach can be used on ",(0,i.jsx)(n.code,{children:"Describe"}),", ",(0,i.jsx)(n.code,{children:"Context"})," and ",(0,i.jsx)(n.code,{children:"It"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"Describe \"Get-FruitBasket\" {\n    It \"Contains <_>\" -ForEach '\u{1F34E}','\u{1F34C}','\u{1F95D}','\u{1F951}','\u{1F347}','\u{1F350}' {\n        Get-FruitBasket | Should -Contain $_\n    }\n}\n\nDescribe \"Get-FruitBasket\" {\n    Context \"Fruit <_>\" -ForEach '\u{1F34E}','\u{1F34C}','\u{1F95D}','\u{1F951}','\u{1F347}','\u{1F350}' {\n        It \"Contains <_> by default\" {\n            Get-FruitBasket | Should -Contain $_\n        }\n\n        It \"Can remove <_> from the basket\" {\n            Remove-FruitBasket -Item $_\n            Get-FruitBasket | Should -Not -Contain $_\n        }\n    }\n    AfterAll {\n        Reset-FruitBasket\n    }\n}\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"-ForEach"})," defines the ",(0,i.jsx)(n.code,{children:"$_"})," variable even when used with an array of hashtables. In that case ",(0,i.jsx)(n.code,{children:"$_"})," will be set to the current hashtable."]})}),"\n",(0,i.jsxs)(n.h2,{id:"using--templates",children:["Using ",(0,i.jsx)(n.code,{children:"<>"})," templates"]}),"\n",(0,i.jsxs)(n.p,{children:["Test and block names can contain values surrounded by ",(0,i.jsx)(n.code,{children:"<>"})," in their name. Those will be considered a template, and will be expanded. Any variable available in scope can be expanded using this syntax, not just the data from ",(0,i.jsx)(n.code,{children:"-ForEach"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'BeforeAll {\n    $apple = \'\u{1F34E}\'\n}\n\nDescribe "<apple>" {\n    It "<apple> <animal>" -ForEach @(\n        @{ Animal = "\u{1F41B}" }\n        @{ Animal = "\u{1F436}" }\n    ) {\n        # ...\n    }\n}\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing \u{1F34E}\n  [+] \u{1F34E} \u{1F41B} 5ms (3ms|2ms)\n  [+] \u{1F34E} \u{1F436} 2ms (1ms|1ms)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["Additionally, the expansion of the string is postponed after the setup for the current block or test. This enables you to expand variables defined in ",(0,i.jsx)(n.code,{children:"BeforeAll"}),", and ",(0,i.jsx)(n.code,{children:"BeforeEach"})," of the current block, even though the code is visually below the name of the block:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"Describe \"<banana>\" {\n    BeforeAll {\n       $banana = '\u{1F34C}'\n    }\n\n    BeforeEach {\n        $giraffe = '\u{1F992}'\n    }\n\n    It \"<banana> <giraffe> <animal>\" {\n        # ...\n    }\n}\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing \u{1F34C}\n  [+] \u{1F34C} \u{1F992}  7ms (5ms|3ms)\n"})}),"\n",(0,i.jsxs)(n.h4,{id:"_-in-template",children:[(0,i.jsx)(n.code,{children:"<_>"})," in template"]}),"\n",(0,i.jsxs)(n.p,{children:["The current item in the provided array is represented by ",(0,i.jsx)(n.code,{children:"$_"})," and can be expanded by using ",(0,i.jsx)(n.code,{children:"<_>"})," template."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Animals " {\n    It "<_>" -ForEach @("\u{1F41B}", "\u{1F436}") {\n        # ...\n    }\n}\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing Animals\n  [+] \u{1F41B} 7ms (2ms|5ms)\n  [+] \u{1F436} 2ms (1ms|1ms)\n"})}),"\n",(0,i.jsxs)(n.h3,{id:"using-dot-navigation-in--template",children:["Using dot-navigation in ",(0,i.jsx)(n.code,{children:"<>"})," template"]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"<>"})," templates allow to navigate through the provided object by using dot-notation. This is useful when the data are not just a flat structure:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Animals" {\n    It "A <animal.emoji> (<name>) goes <animal.sound>" -ForEach @(\n        @{\n            Name = "cow"\n            Animal = @{\n                Sound = "Mooo"\n                Emoji = "\u{1F404}"\n            }\n        }\n\n        @{\n            Name = "fox"\n            Animal = @{\n                Sound = "Ring-ding-ding-ding-dingeringeding!"\n                Emoji = "\u{1F98A}"\n            }\n        }\n    ) {\n        # ...\n    }\n}\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing Animals\n  [+] A \u{1F404} (cow) goes Mooo 12ms (1ms|11ms)\n  [+] A \u{1F98A} (fox) goes Ring-ding-ding-ding-dingeringeding! 2ms (1ms|1ms)\n"})}),"\n",(0,i.jsx)(n.h3,{id:"escaping",children:"Escaping"}),"\n",(0,i.jsxs)(n.p,{children:["Before the template string is expanded every ",(0,i.jsx)(n.code,{children:"$"})," and ",(0,i.jsx)(n.code,{children:"`"})," in the text is escaped. This allows you to put literals, such as ",(0,i.jsx)(n.code,{children:"$null"})," in your test names, and still use the template to expand the value:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Describe "Fruit" -ForEach "\u{1F34E}", "\u{1F350}" {\n    # with single quoted string\n    It \'Getting <_> returns $null\' {\n        # ...\n    }\n\n    # with double quoted string\n    It "Getting <_> returns `$null" {\n        # ...\n    }\n}\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing Fruit\n  [+] Getting \u{1F34E} returns $null 3ms (1ms|2ms)\n  [+] Getting \u{1F34E} returns $null 2ms (1ms|1ms)\n\nDescribing Fruit\n  [+] Getting \u{1F350} returns $null 3ms (1ms|3ms)\n  [+] Getting \u{1F350} returns $null 1ms (1ms|1ms)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["To avoid a ",(0,i.jsx)(n.code,{children:"<"})," from being considered a template use  ",(0,i.jsx)(n.code,{children:"`<"})," to escape it. This allows you to put greater than and less than in your test names. Or to wrap values in ",(0,i.jsx)(n.code,{children:"<>"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"# with single quoted string\nDescribe 'When x `< 4, x: <_>' -ForEach @(1..4) {\n    It 'x: `<<_>`>' {\n        # ...\n    }\n}\n\n# with double quoted string\nDescribe \"When x ``< 4, x: <_>\" -ForEach @(1..4) {\n    It \"x: ``<<_>``>\" {\n        # ...\n    }\n}\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Describing When x < 4, x: 1\n  [+] x: <1> 3ms (1ms|3ms)\n\nDescribing When x < 4, x: 2\n  [+] x: <2> 6ms (0ms|6ms)\n\nDescribing When x < 4, x: 3\n  [+] x: <3> 5ms (1ms|5ms)\n\nDescribing When x < 4, x: 4\n  [+] x: <4> 4ms (0ms|4ms)\n"})}),"\n",(0,i.jsx)(n.h4,{id:"internals",children:"Internals"}),"\n",(0,i.jsxs)(n.p,{children:["The value in the string is escaped by adding ",(0,i.jsx)(n.code,{children:"`"})," before every ",(0,i.jsx)(n.code,{children:"$"})," and ",(0,i.jsx)(n.code,{children:"`"}),". Every template is prefixed by ",(0,i.jsx)(n.code,{children:"$"}),", and then the string is expanded:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:'"<x> should not be `$null"\n\n# because this is double quoted string it will be\n# expanded by powershell to\n\n<x> should not be $null\n\n# then escaped by us to\n<x> should not be `$null\n\n# template is replaced\n$x should not be `$null\n\n# and then it is evaluated in the appropriate script scope\n$x = 1\n& { "$x should not be `$null" }\n\n# giving the final text\n1 should not be $null\n'})}),"\n",(0,i.jsx)(n.h4,{id:""}),"\n",(0,i.jsx)(n.h2,{id:"providing-external-data-to-tests",children:"Providing external data to tests"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:".Tests.ps1"})," script is a PowerShell script as any other and you can use the ",(0,i.jsx)(n.code,{children:"param"})," block in it. Script parameters are available in both ",(0,i.jsx)(n.code,{children:"Discovery"})," and ",(0,i.jsx)(n.code,{children:"Run"}),". This is very useful when reusing a single test file with multiple data sets. For example when writing a generic test suite that ensures that correct style is used in a given script file:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",metastring:'title="CodingStyle.Tests.ps1"',children:'param (\n    [Parameter(
1Mandatory)]\n    [string] $File\n)\n\nBeforeAll {\n    $content = Get-Content $File\n}\n\nDescribe "File - <file>" {\n    Context "Whitespace" {\n        It "There is no extra whitespace following a line" {\n            # ...\n        }\n\n        It "File ends with an empty line" {\n            # ...\n        }\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The external data are then provided to the test by ",(0,i.jsx)(n.code,{children:"-Data"})," parameter on ",(0,i.jsx)(n.code,{children:"New-PesterContainer"}),", in the same manner ",(0,i.jsx)(n.code,{children:"-ForEach"})," would be used on ",(0,i.jsx)(n.code,{children:"Describe"})," or ",(0,i.jsx)(n.code,{children:"It"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"$container = New-PesterContainer -Path 'CodingStyle.Tests.ps1' -Data @{ File = \"Get-Emoji.ps1\" }\nInvoke-Pester -Container $container -Output Detailed\n"})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Running tests from 'C:\\p\\style\\CodingStyle.Tests.ps1'\nDescribing File - Get-Emoji.ps1\n Context Whitespace\n   [+] There is no extra whitespace following a line 30ms (1ms|30ms)\n   [+] File ends with an empty line 2ms (1ms|1ms)\nTests completed in 445ms\nTests Passed: 2, Failed: 0, Skipped: 0 NotRun: 0\n"})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"$PSBoundParameters"})," is not available in Pester tests. Reference parameters by their variables like ",(0,i.jsx)(n.code,{children:"$File"})," in the example above."]})}),"\n",(0,i.jsx)(n.h4,{id:"re-using-the-same-test-file",children:"Re-using the same test file"}),"\n",(0,i.jsx)(n.p,{children:"In the scenario above we tested just a single file, but chances are we want to run those style tests for every file in the repository. This can be achieved by generating one data item for each file:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"$files = 'Get-Emoji.ps1', 'Get-Planet.ps1'\n$containers = $files | ForEach-Object {\n    New-PesterContainer -Path 'CodingStyle.Tests.ps1' -Data @{ File = $_ }\n}\n\nInvoke-Pester -Container $containers -Output Detailed\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will run the test file twice, once for each file. You could even grab all ",(0,i.jsx)(n.code,{children:".ps1"})," files in the current Path and test them, just by using ",(0,i.jsx)(n.code,{children:"$files = Get-ChildItem -Filter '*.ps1' -Recurse"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"-Data"})," parameter takes an array of hashtables. As an alternative to the code above, you also attach all the test data to a single container:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"$files = 'Get-Emoji.ps1', 'Get-Planet.ps1'\n$data = $files | ForEach-Object {\n    @{ File = $_ }\n}\n\n$container = New-PesterContainer -Path 'CodingStyle.Tests.ps1' -Data $data\nInvoke-Pester -Container $container -Output Detailed\n"})}),"\n",(0,i.jsx)(n.p,{children:"There is no advantage in using one over the other, choose the one that suits your needs better."}),"\n",(0,i.jsx)(n.h4,{id:"re-using-the-same-data-set",children:"Re-using the same data set"}),"\n",(0,i.jsx)(n.p,{children:"In the example above we had a single test file, and multiple different data sets. We can also have the opposite. A single data set used by multiple test files:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"$data =  @{ File = \"Get-Emoji.ps1\" }\n$containers = @(\n    (New-PesterContainer -Path 'CodingStyle.Tests.ps1' -Data $data)\n    (New-PesterContainer -Path 'BadWords.Tests.ps1' -Data $data)\n)\nInvoke-Pester -Container $containers -Output Detailed\n\n# or simply\n\n$data =  @{ File = \"Get-Emoji.ps1\" }\n$container = New-PesterContainer -Path 'CodingStyle.Tests.ps1', 'BadWords.Tests.ps1' -Data $data\nInvoke-Pester -Container $container -Output Detailed\n"})}),"\n",(0,i.jsx)(n.h4,{id:"wildcards",children:"Wildcards"}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"New-PesterContainer"})," resolves the ",(0,i.jsx)(n.code,{children:"-Path"})," parameter the same way ",(0,i.jsx)(n.code,{children:"Invoke-Pester"})," does. You can use it to provide a wildcard path to run all files matching the pattern. For example to run all *Style tests against all files in the current directory:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:"$files = Get-ChildItem -Filter '*.ps1' -Recurse\n$data = $files | ForEach-Object {\n    @{ File = $_.FullName }\n}\n\n\n$containers = New-PesterContainer -Path '*Style.Tests.ps1' -
1Data $data\nInvoke-Pester -Container $containers -Output Detailed\n"})}),"\n",(0,i.jsx)(n.h2,{id:"beforediscovery",children:(0,i.jsx)(n.code,{children:"BeforeDiscovery"})}),"\n",(0,i.jsxs)(n.p,{children:["In Pester v4 it was normal to place code directly on top of the script file, or directly into the body of ",(0,i.jsx)(n.code,{children:"Describe"})," and ",(0,i.jsx)(n.code,{children:"Context"}),". Pester v5 discourages this, because all code directly in script or in ",(0,i.jsx)(n.code,{children:"Describe / Context"})," body will run during ",(0,i.jsx)(n.code,{children:"Discovery"}),". This leads to unexpected results."]}),"\n",(0,i.jsxs)(n.p,{children:["BUT in some cases, especially when generating tests, putting code directly in script body is okay. ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"})," was introduced to show that the code is like this intentionally, and not by accident. Wrapping code into ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"})," has no impact on its execution. It should be used everywhere where code is intentionally placed outside of a Pester controlled leaf-block (see ",(0,i.jsx)(n.a,{href:"discovery-and-run",children:"Discovery and Run"}),"). That is on top of files, or directly in body of ",(0,i.jsx)(n.code,{children:"Describe / Context"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["Here for example I generate one ",(0,i.jsx)(n.code,{children:"Describe"})," for each script file, instead of passing the list of files externally. I need this code to run during ",(0,i.jsx)(n.code,{children:"Discovery"})," to generate those blocks. ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"})," is used there to show that this code placement is intentional:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'BeforeDiscovery {\n    $files = Get-ChildItem -Path $PSScriptRoot -Filter \'*.ps1\' -Recurse\n}\n\nDescribe "File - <_>" -ForEach $files {\n    Context "Whitespace" {\n        It "There is no extra whitespace following a line" {\n            # ...\n        }\n\n        It "File ends with an empty line" {\n            # ...\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.h2,{id:"migrating-from-pester-v4",children:"Migrating from Pester v4"}),"\n",(0,i.jsxs)(n.p,{children:["There are two main things to take into account when Data driven tests in Pester v5: The ",(0,i.jsx)(n.a,{href:"#execution-is-not-top-down",children:"execution is not top down"})," like in V4 but done in two phases ",(0,i.jsx)(n.code,{children:"Discovery"})," and ",(0,i.jsx)(n.code,{children:"Run"}),". Variables from ",(0,i.jsx)(n.code,{children:"Discovery"})," are not available in ",(0,i.jsx)(n.code,{children:"Run"}),", unless you explicitly attach them to a ",(0,i.jsx)(n.code,{children:"Describe"}),", ",(0,i.jsx)(n.code,{children:"Context"})," or ",(0,i.jsx)(n.code,{children:"It"})," using ",(0,i.jsx)(n.code,{children:"Foreach"})," or ",(0,i.jsx)(n.code,{children:"TestCases"})]}),"\n",(0,i.jsxs)(n.p,{children:["This has big impact the classic pattern of using ",(0,i.jsx)(n.code,{children:"foreach"})," to generate tests."]}),"\n",(0,i.jsx)(n.h3,{id:"execution-is-not-top-down",children:"Execution is not top down"}),"\n",(0,i.jsxs)(n.p,{children:["Pester v5 introduces a new two phase execution. In the first phase called ",(0,i.jsx)(n.code,{children:"Discovery"}),", it will run your whole test script from top to bottom. It will also run all ScriptBlocks that you provided to any ",(0,i.jsx)(n.code,{children:"Describe"}),", ",(0,i.jsx)(n.code,{children:"Context"})," and ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"}),". It will collect the ScriptBlocks you provided to ",(0,i.jsx)(n.code,{children:"It"}),", ",(0,i.jsx)(n.code,{children:"BeforeAll"}),", ",(0,i.jsx)(n.code,{children:"BeforeEach"}),", ",(0,i.jsx)(n.code,{children:"AfterEach"})," and ",(0,i.jsx)(n.code,{children:"AfterAll"}),", but won't run them until later."]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{style:{textAlign:"left"},children:"Phase"}),(0,i.jsx)(n.th,{style:{textAlign:"left"},children:"V4"}),(0,i.jsx)(n.th,{style:{textAlign:"left"},children:"V5 Discovery"}),(0,i.jsx)(n.th,{style:{textAlign:"left"},children:"V5 Run"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"BeforeAll"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"BeforeEach"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"It"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"AfterEach"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"AfterAll"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"BeforeDiscovery"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"N/A"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"Describe"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:(0,i.jsx)(n.code,{children:"Context"})}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"Other"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u2714\uFE0F"}),(0,i.jsx)(n.td,{style:{textAlign:"left"},children:"\u274C"})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:["Other, is any script outside of ",(0,i.jsx)(n.code,{children:"It"}),", ",(0,i.jsx)(n.code,{children:"BeforeAll"}),", ",(0,i.jsx)(n.code,{children:"BeforeEach"}),", ",(0,i.jsx)(n.code,{children:"AfterEach"})," and ",(0,i.jsx)(n.code,{children:"AfterAll"}),". You see that this code behaves like the new ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"})," block and thus for clarity on when script will be run its advised to use the ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["In simple terms this means that the script below will run until the last line during ",(0,i.jsx)(n.code,{children:"Discovery"}),". But no test will be executed:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'Write-Host "We are starting with discovery."\nDescribe "d" {\n    Write-Host "We are finding tests in this describe."\n    It "i" {\n        Write-Host "I am running!"\n    }\n\n    Write-Host "We are leaving this describe."\n}\n\nWrite-Host "We are done with discovery!"\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Starting discovery in 1 files.\nDiscovering in C:\\p\\g.Tests.ps1.\nWe are starting with discovery.\nWe are finding tests in this describe.\nWe are leaving this describe.\nWe are done with discovery!\nFound 1 tests. 35ms\nDiscovery finished in 43ms.\n\nRunning tests from 'C:\\p\\g.Tests.ps1'\nDescribing d\nI am running!\n  [+] i 5ms (2ms|3ms)\nTests completed in 256ms\n"})}),"\n",(0,i.jsxs)(n.p,{children:['Notice that "We are done with discovery!" is placed at the end of the script, but is printed before "I am running!". This is because we postpone the execution of ',(0,i.jsx)(n.code,{children:"It"})," until the ",(0,i.jsx)(n.code,{children:"Run"})," phase."]}),"\n",(0,i.jsxs)(n.h3,{id:"variables-defined-during-discovery-are-not-available-in-run",children:["Variables defined during ",(0,i.jsx)(n.code,{children:"Discovery"})," are not available in ",(0,i.jsx)(n.code,{children:"Run"})]}),"\n",(0,i.jsxs)(n.p,{children:["Defining a variable directly in the body of the script, will make it available during ",(0,i.jsx)(n.code,{children:"Discovery"}),", but it won't be available during ",(0,i.jsx)(n.code,{children:"Run"}),". You can see that the test failed because ",(0,i.jsx)(n.code,{children:"$n
1ame"})," is not defined."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'$name = "Jakub"\n\nDescribe "d" {\n    It "My name is: $name" {\n        $name | Should -be "Jakub"\n    }\n}\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"Starting discovery in 1 files.\nDiscovering in C:\\p\\g.Tests.ps1.\nFound 1 tests. 21ms\nDiscovery finished in 65ms.\n\nRunning tests from 'C:\\p\\g.Tests.ps1'\nDescribing d\n  [-] My name is: Jakub 106ms (103ms|3ms)\n   Expected 'Jakub', but got $null.\n   at $name | Should -be \"Jakub\", C:\\p\\g.Tests.ps1:5\n   at <ScriptBlock>, C:\\p\\g.Tests.ps1:5\nTests completed in 436ms\nTests Passed: 0, Failed: 1, Skipped: 0 NotRun: 0\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This is especially confusing because ",(0,i.jsx)(n.code,{children:"$name"})," was correctly expanded in the name of the test. But if you think about it, it is logical. The script is running till the end, so the string ",(0,i.jsx)(n.code,{children:'"My name is: $name"'})," is expanded during ",(0,i.jsx)(n.code,{children:"Discovery"})," where the ",(0,i.jsx)(n.code,{children:"$name"})," variable ",(0,i.jsx)(n.em,{children:"is"})," available."]}),"\n",(0,i.jsxs)(n.h3,{id:"moving-away-from-foreach",children:["Moving away from ",(0,i.jsx)(n.code,{children:"foreach"})]}),"\n",(0,i.jsx)(n.p,{children:"Those two limitations mean that this pattern, is difficult to use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'$files = Get-ChildItem "../src/*.ps1" -Recurse\nforeach ($file in $files) {\n    Describe "$file" {\n        It "$file - has help" {\n            $content = Get-Content $file\n            # ...\n        }\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The ",(0,i.jsx)(n.code,{children:"$file"})," variable won't be defined in the ",(0,i.jsx)(n.code,{children:"It"})," and the test will fail. You can work around this problem by specifying a single item ",(0,i.jsx)(n.code,{children:"-ForEach"})," to attach the value to the block. ",(0,i.jsx)(n.code,{children:"-ForEach"})," (and ",(0,i.jsx)(n.code,{children:"-TestCases"}),") will inspect the provided value, and if it is a hashtable, it will define a variable for each key in that hashtable."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'$files = Get-ChildItem "../src/*.ps1" -Recurse\nforeach ($file in $files) {\n    Describe "$file" -ForEach { File = $file } {\n        It "$file - has help" {\n            $content = Get-Content $file\n            # ...\n        }\n    }\n}\n'})}),"\n",(0,i.jsxs)(n.p,{children:["This will take the value of ",(0,i.jsx)(n.code,{children:"$file"})," during ",(0,i.jsx)(n.code,{children:"Discovery"})," and attach it to that ",(0,i.jsx)(n.code,{children:"Describe"})," block, and then during ",(0,i.jsx)(n.code,{children:"Run"})," it will define a new variable ",(0,i.jsx)(n.code,{children:"$file"})," with the same value."]}),"\n",(0,i.jsxs)(n.p,{children:["Next step is to move to ",(0,i.jsx)(n.code,{children:"-ForEach"})," functionality entirely:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'BeforeDiscovery {\n    $files = Get-ChildItem "../src/*.ps1" -Recurse\n}\n\nDescribe "<file>" -ForEach $files {\n    BeforeAll {\n        # Renaming the automatic $_ variable to $file\n        # to make it easier to work with\n        $file = $_\n    }\n    It "<file> - has help" {\n        $content = Get-Content $file\n        # ...\n    }\n}\n'})}),"\n",(0,i.jsx)(n.p,{children:"There are three notable changes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"$files"})," are defined inside of ",(0,i.jsx)(n.code,{children:"BeforeDiscovery"})," block, to show that this code is running in ",(0,i.jsx)(n.code,{children:"Discovery"})," intentionally, and not by accident"]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"$files"})," is provided directly to ",(0,i.jsx)(n.code,{children:"-ForEach"}),". This will generate one ",(0,i.jsx)(n.code,{children:"Describe"})," for each item in ",(0,i.jsx)(n.code,{children:"$file"}),", and will define the current item as ",(0,i.jsx)(n.code,{children:"$_"})," which is available in both ",(0,i.jsx)(n.code,{children:"Discovery"})," and ",(0,i.jsx)(n.code,{children:"Run"}),"."]}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["\n",(0,i.jsxs)(n.p,{children:["The names of tests are using the ",(0,i.jsx)(n.code,{children:"<>"})," template to expand the variable ",(0,i.jsx)(n.code,{children:"$file"})," during ",(0,i.jsx)(n.code,{children:"Run"}),". Any variable in scope can be used for that expansion, including the variables defined in the ",(0,i.jsx)(n.code,{children:"BeforeAll"})," that is contained directly inside of the current ",(0,i.jsx)(n.code,{children:"Describe"}),"."]}),"\n"]}),"\n"]}),"\n",(0,i.jsxs)(n.h3,{id:"another-variation-on-foreach",children:["Another variation on ",(0,i.jsx)(n.code,{children:"foreach"})]}),"\n",(0,i.jsxs)(n.p,{children:["One more common approach is to put common test setup directly in the ",(0,i.jsx)(n.code,{children:"Describe"})," block to ensure that the file will be loaded only once:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'$files = Get-ChildItem "../src/*.ps1" -Recurse\nforeach ($file in $files) {\n    Describe "$file" {\n        $content = Get-Content $file\n        It "$file - has help" {\n            # ...\n        }\n    }\n}\n'})}),"\n",(0,i.jsx)(n.p,{children:"This approach can still be easily converted to Pester v5:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-powershell",children:'BeforeDiscovery {\n    $files = Get-ChildItem "../src/*.ps1" -Recurse\n}\n\nDescribe "<file>" -ForEach $files {\n    BeforeAll {\n        # Renaming the automatic $_ variable to $file\n        # to make it easier to work with\n        $file = $_\n        $content = Get-Content $file\n    }\n    It "<file> - has help" {\n        # ...\n    }\n}\n'})})]})}function u(e={}){let{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(x,{...e})}):x(e)}},7008(e,n,t){t.d(n,{R:()=>r,x:()=>a});var s=t(1763);let i={},l=s.createContext(i);function r(e){let n=s.useContext(l);return s.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),s.createElement(l.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.