Exercise: Test Your Tool
Give the RecipeBox module a manifest with New-ModuleManifest, then write five Pester tests that work on a copy of the recipes in TestDrive:, and a check proves they're good enough by breaking RecipeBox five ways and expecting a test to fail each time.
Freelancer · PowerShell · Updated
A tool you use every week will change: a new category, a faster search, a fix for a bug someone found. Every change can quietly break something that used to work, and the recipe box is no different. In this exercise, RecipeBox becomes a proper module, with a manifest, and gets the tests that will catch those breaks for you from now on. How do you know your tests are any good? The check finds out the way testers do: it breaks RecipeBox on purpose, five different ways, and expects one of your tests to fail each time.
Get the exercise code
Open this lesson's GitHub repository, github.com/ask-codey/exercise-powershell-test-your-tool, also linked from the Exercise box beside the lesson. Click Code, then Download ZIP, and unzip it into your terminal-practice folder. Or clone it with Git.
The folder holds:
RecipeBox\RecipeBox.psm1: the recipe box from Exercise: A Recipe Box Module, grown a little.Remove-Recipeis new, with-WhatIf, and every command takes-Path, so a test can point it at a copy of the box instead of your real one. Don't change it.test-data\recipes.json: five test recipes, two of them Baking, and Lemon Garlic Pasta, which takes exactly 30 minutes.RecipeBox.Tests.ps1: your tests, with one example written.Check.Tests.ps1: the check. You don't need to change it.
What to do
Open PowerShell 7 in the exercise folder, the one with RecipeBox.Tests.ps1 in it.
Make the manifest. Use
New-ModuleManifestto makeRecipeBox\RecipeBox.psd1, besideRecipeBox.psm1, as in Your Own Module. Give it-RootModule RecipeBox.psm1, a version and a description, and-FunctionsToExportwithGet-Recipe,Add-RecipeandRemove-Recipe, leaving out the two helpers. Check it withTest-ModuleManifest.Run the example.
Invoke-Pester .\RecipeBox.Tests.ps1 -Output Detailedshows one passing test. Here's how the file starts; every test gets a fresh copy of the five recipes inTestDrive:, in$box:Describe 'RecipeBox' { BeforeEach { $box = Join-Path $TestDrive 'recipes.json' Copy-Item -Path "$PSScriptRoot\test-data\recipes.json" -Destination $box } It 'Get-Recipe returns every recipe in the box' { Get-Recipe -Path $box | Should -HaveCount 5 }Write five more tests, one
Itfor each:Get-Recipe -Category Bakingreturns only the baking recipes.Get-Recipe -MaxMinutes 30includes a recipe that takes exactly 30 minutes.Add-Recipesaves the new recipe, soGet-Recipefinds it afterwards.Add-Reciperefuses a name that's already in the box.Remove-Recipe -WhatIfleaves the recipe in the box.
Give every RecipeBox command -Path $box, so your tests never touch your real recipe box.
Check your work
The check uses Pester. If you haven't installed it yet, install it once:
Install-PSResource Pester
Then, from the exercise folder, run your own tests, then the check:
Invoke-Pester .\RecipeBox.Tests.ps1 -Output Detailed
Invoke-Pester .\Check.Tests.ps1
At first most of the check's tests fail. That's expected: the manifest turns the first three green. Then the check runs your tests on RecipeBox as it is, where all of them must pass, and on five broken copies, where at least one must fail. A failing check names the break your tests missed and gives a hint, for example in this copy, Add-Recipe returns the new recipe but never saves it, and no test noticed. After Add-Recipe, look for the recipe with Get-Recipe. It starts a fresh PowerShell for each run, so give it up to half a minute.
If PowerShell says the check can't be loaded because it is not digitally signed, Windows has marked the downloaded files as coming from the internet: from the exercise folder, run Get-ChildItem -Recurse | Unblock-File once, then try again.
Hints
- Try it at the prompt first.
Import-Module .\RecipeBox\RecipeBox.psd1 -Force, thenGet-Recipe -Category Baking -Path .\test-data\recipes.json: see the answer, then write theShouldthat expects it. (OnlyGet-Recipeis safe on the test data itself; the others change it.) - Check the right thing.
(Get-Recipe -Category Baking -Path $box).Namegives the names of the recipes it found, andShould -Be 'Apple Crumble', 'Banana Bread'checks the whole list. - The edge matters. "Exactly 30 minutes" is where
-leand-ltdiffer:Should -Contain 'Lemon Garlic Pasta'. - A command that should fail goes in braces:
{ Add-Recipe ... } | Should -Throw(Testing with Pester). - A rehearsal changes nothing. After
Remove-Recipe -WhatIf,Get-Recipe -Nameshould still find exactly one.
When you're done
Your own tests are all green:
Tests Passed: 6, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0
And so is the check:
Tests Passed: 11, Failed: 0, Skipped: 0, Inconclusive: 0, NotRun: 0
Now run Invoke-ScriptAnalyzer -Path .\RecipeBox -Recurse, as in PSScriptAnalyzer: A Second Pair of Eyes. What does it say about the manifest, and how would you fix it?
Submit your exercise
The exercise is how you finish this lesson. When your work is done, put it on GitHub in a repo of your own, then submit that repo's address here.
On GitHub, click +, then New repository. Name it (for example
exercise-powershell-test-your-tool), choose Public, and click Create repository. Leave out the README: your folder already has one.In a terminal in your exercise folder (PowerShell works), send your work to your new repo. If you downloaded the ZIP:
git init -b main git add . git commit -m "My solution" git remote add origin https://github.com/your-name/exercise-powershell-test-your-tool.git git push -u origin mainIf you cloned the starter instead, point your copy at your own repo, then commit and push:
git remote set-url origin https://github.com/your-name/exercise-powershell-test-your-tool.git git add . git commit -m "My solution" git push -u origin mainPaste your repo's address, such as
https://github.com/your-name/exercise-powershell-test-your-tool, into Submit your exercise on this page. The site checks that the repo is public and holds your commits, and then the lesson is complete.
Changed something after you submitted? Push it, and submit again: your latest submission is the one that counts.
So what
Your recipe box now has a label and a safety net: change it whenever you like, and six green checks tell you in seconds that it still does its job.