Correct TestDrive usage

Hello,
I’m trying to test a script which stores some files on hard disk. During the test I would like to store a file to TestDrive:\ and check if it was indeed created. The problem is that file always gets created in “$env:TEMP\myfile.txt”. Could you please explain what am I missing here?

#script.ps1
Function Get-FilePath {
    return "$env:TEMP\myfile.txt"
}
"Some Content" | Out-File (Get-FilePath)
#script.Tests.ps1
Describe "Script" {
    Function Get-FilePath {}
    Mock Get-FilePath { return "TestDrive:\myFile.txt" }
    . "$PSScriptRoot\Script.ps1"
    It "File should be created in TestDrive" {
        Test-Path (Get-FilePath) | Should Be $true
    }
    It "File should not be created in $env:Temp" {
        Test-Path "$env:TEMP\myfile.txt" | Should Be $false
    }
    if (Test-Path "$env:TEMP\myfile.txt") {
        Remove-Item "$env:TEMP\myfile.txt"
    } 
}

You do not need to define Get-FilePath again in your test. The mock will take care of that. When you do that, your mock is applying to that function and not the one defined in your script.ps1 file.

Hi Adam,
Thanks for reply. If I’m not defining it, I get CommandNotFoundException and if I move script dot-source up, then it creates file in $env:temp and in It block it looks for file in TestDrive.

Ah. I see. This is where code refactoring comes into play. It seems like you’re just testing if Get-FilePath returns what you expect it to since you don’t have the actual file creation step inside of that function. If this is the case, I suggest remove the Out-File functionality from the script altogether and building a simple test to ensure that Get-FilePath returns the expected string like this:

describe 'Get-FilePath' {
   $result = . $PSSscriptRoot\script.ps1

   it 'returns the temp file path' {
       $result | should be 'C:\Windows\Temp\myfile.txt'
   }
}

If you do need to confirm a function creates a file in a specific location you could also use a mock assertion to ensure Add-Content in this case used the expected path.

script.ps1

function New-File {
    param()
    Add-Content -Path "$env:TEMP\myfile.txt" -Value ''
}

Then the test would look like this:

describe 'New-File' {
    mock 'Add-Content'
    . $PSScriptRoot\script.ps1

    it 'should create the file in the expected location' {
        Assert-MockCalled -CommandName 'Add-Content' -Times 1 -ParameterFilter { $Path -eq 'C:\Users\Adam\AppData\Local\Temp\myfile.txt' }
    }
}

Heh, that makes sense. Ended up with this

$settingsContent = @"
#Spark Settings
#Mon May 09 11:36:00 EEST 2016
server=chat.runway.lv
showOfflineUsers=false
passwordSaved=false
username=$env:USERNAME
lastUpdateCheck=1460015572859
autoLoginEnabled=false
loginAsInvisibleEnabled=false
offlineGroupVisible=true
showEmptyGroups=false
"@

Function Get-SparkPropertiesFile {
    Write-Output (Join-Path $env:USERPROFILE "AppData\Roaming\Spark\spark.properties")
}

Function New-PropertiesFile {
    if (!(Test-Path (Split-Path (Get-SparkPropertiesFile))))
    {
        mkdir (Split-Path (Get-SparkPropertiesFile))
        try {
            Add-Content -Value $settingsContent -Path (Get-SparkPropertiesFile) -Encoding UTF8 -ErrorAction Stop
        } 
        catch {
            Write-Log -Message "Failed to create new properties file" -Level error -Path $env:gpLogfile
        }
        
    }
}
if (($env:gpObject -eq 'User') -and ($env:gpState -eq 'Logon')) {
    New-PropertiesFile
} 
$projectRoot = (get-item $PSScriptRoot).parent.parent.parent.FullName
$ScriptsDir = "$projectRoot\GPScripts\Scripts"
$scriptName = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '.Tests.ps1', ''


Describe "User_Set-Spark" {
    $env:gpObject = 'User'
    $env:gpState = 'Logon'

    Mock 'Add-Content'
    . "$ScriptsDir\$scriptName\$scriptName.ps1"
    
    It "Should create new properties file" {
        Assert-MockCalled -CommandName 'Add-Content' -Times 1 -ParameterFilter { $Path -eq "$env:USERPROFILE\AppData\Roaming\Spark\spark.properties" }
    }
}

Thank you. Looking forward to your pester talk today. Cheers!

For some reason my previous message was treated as spam. Just wanted to say thank you for help. Everything working smooth now.