help testing a function that relies on the module to be loaded.

Welcome Forums Pester help testing a function that relies on the module to be loaded.

This topic contains 6 replies, has 2 voices, and was last updated by

 
Participant
3 months, 2 weeks ago.

  • Author
    Posts
  • #105524

    Participant
    Points: 22
    Rank: Member

    My psm1 file dot sources all functions in my development setup, I export all function module members. I'm trying to learn Pester and I'm stuck on figuring out how to have the test.ps1 file load the function.ps1 file which relies on importing the module. Here's a sample of my folder structure if this helps.

    This function will eventually compare the repo latest version with the current version and alert the user that there is an update. Initially, I need to get the module version from the function. The problem is I'm not sure how to get the pester test to work correctly.

    C:\..\Docs
    C:\..\en-us
    C:\..\Private\Get-RepoModuleVersion.ps1
    C:\..\Public
    C:\..\Tests\Get-RepoModuleVersion.test.ps1
    C:\..\expFTP.psd1
    C:\..\expFTP.psm1
    

    Get-RepoModuleVersion.ps1

    Function Get-RepoModuleVersion {
        [CmdletBinding()]
        Param(
            [Parameter()]
            [Switch]$Latest
        )
    
        Begin {}
        
        Process {
            (Get-command $MyInvocation.MyCommand).version
        }
    
        End {}
    }
    

    Get-RepoModuleVerson.test.ps1

    $projectRoot = Resolve-Path "$PSScriptRoot\.."
    ."$projectRoot\Private\Get-RepoModuleVersion.ps1"
    
    Import-module "$projectRoot\expftp.psd1" -force
    InModuleScope expFTP {
        Describe 'Get-RepoModuleVersion' {
            Mock 'Get-command' {'4.6.3.7'}
            Context 'Input' {
                {Get-RepoModuleVersion -Latest } | Should be '4.6.3.7'
            }
            Context 'Execution' {}
            Context 'Output' {}
        }
    }
    
  • #105566

    Keymaster
    Points: 1,625
    Helping HandTeam Member
    Rank: Community Hero

    I'm perhaps not following – wouldn't you just import the module?

  • #105572

    Participant
    Points: 22
    Rank: Member

    Thank's Don. I noticed I left out the It block by mistake and didn't catch it. The other issue Is I don't think I was mocking get-command correctly as I'm mocking it with a string then calling a property of that object. I did rewrite my function and test another way and it passes now. I also renamed the function.

    If my logic is not too difficult to follow, do you think my test is adequate or should I add additional tests? In a nutshell, the function will be called from the Begin Blocks of my public functions to notify the end user that there is an update to the module by comparing the local and remote repo versions.

    Compare-expFtpRepoModuleVersion.ps1

    Function Compare-expFtpRepoModuleVersion {
        [CmdletBinding()]
        Param()
    
        Begin {}
        
        Process {
            $LocalModuleVersion = (Get-command $MyInvocation.MyCommand)
            Try {
                $RemoteModuleVersion = Find-Module -Name $LocalModuleVersion.Source -ErrorAction Stop
                if ($RemoteModuleVersion){
                    if ($LocalModuleVersion.Version -LT $RemoteModuleVersion.Version) {
                        $Update = 'Yes'
                    }
                    Else {
                        $Update = 'No'
                    }
                    $Properties = @{
                        LocalVersion  = $LocalModuleVersion.Version
                        RemoteVersion = $RemoteModuleVersion.Version
                        CheckTime     = (get-date)
                        Update        = $Update
                        Module        = $LocalModuleVersion.Source
            
                    }
                    $obj = New-Object -TypeName PSObject -Property $properties
                    Set-Variable -Name "$($LocalModuleVersion.Source)Module" -Value $obj -Scope Global
    
                }
            }
            Catch {}
        }
    
        End {}
    }
    

    Compare-expFtpRepoModuleVersion.test.ps1

    $projectRoot = Resolve-Path "$PSScriptRoot\.."
    ."$projectRoot\Private\Compare-expFtpRepoModuleVersion.ps1"
    
    Import-module "$projectRoot\expftp.psd1" -force
    InModuleScope expFTP {
        Describe 'Get-RepoModuleVersion' {
            Mock 'Get-command'
            Context 'Input' {
                it 'should return the correct type' {
                    {Compare-expFtpRepoModuleVersion} | Should beoftype PSCustomObject
                }
            }
            Context 'Execution' {}
            Context 'Output' {}
        }
    }
    
  • #105575

    Keymaster
    Points: 1,625
    Helping HandTeam Member
    Rank: Community Hero

    So, a trick with testing is to make sure you're also testing the "negative." Meaning, don't just check to make sure it does the correct thing, make sure it also deals well with an "incorrect" situation.

    Additionally, I wouldn't return a PSCustomObject. Give that thing a custom type name and check for that – PSCustomObject is way too common.

    Right now, you're just checking for a type name – do you need to care about the properties, or their values, for a given input? What about situations where "something went wrong," like something you expected to exist isn't installed? Will it deal with those situations correctly?

  • #105578

    Participant
    Points: 22
    Rank: Member

    could you elaborate on a custom type name? I don't think I'm familiar with that. I would also need to test the object to make sure the properties are returned as expected. I guess for that I would have to mock Get-Command and Find-Module with some fake properties that resemble the actual format of a real Get-Command and Find-Module call. As for testing a failure, I think mocking Get-Command and/or Find-Module with a Throw should do the trick, right?

    I'll have to do a bit of research and go further into the Pester Book

  • #105581

    Keymaster
    Points: 1,625
    Helping HandTeam Member
    Rank: Community Hero

    $obj.psobject.typenames.insert(0,"My.Custom.Type.Name")

    Or, peruse "Learn PowerShell Scripting in a Month of Lunches," which covers it pretty extensively ;).

    I guess for that I would have to mock Get-Command and Find-Module with some fake properties that resemble the actual format of a real Get-Command and Find-Module call.

    Well, no. Like, what's the goal? Are you testing to see if Get-Command works? Don't bother; if it's broken, you can't fix it. You should be testing YOUR commands, not built-in ones. Presume that Get-Command works correctly, because if it doesn't, we're all screwed big-time. Same with Find-Module; you don't test other people's commands. So if the logic here is, "I want to use Get-Command to make sure my command is installed," then you don't write a test for that. Get-Command will work as designed.

  • #105583

    Participant
    Points: 22
    Rank: Member

    Got it! I didn't read Scripting in a month of lunches, but I do have the PowerShell scripting and Toolmaking book, so I think I will have to go back and review. Thanks for the help!

The topic ‘help testing a function that relies on the module to be loaded.’ is closed to new replies.