I have an issue, where I try to mock the Windows built-in cmdlet Expand-Archive
in a pester unit test. Somehow, during the execution the original cmdlet is executed rather than the mocked variant. I've tried putting the Expand-Archive
mock outside of the Describe
scope, but that didn't work.
Here is the module I'd like to test:
class Validator {
[bool] Validate([string] $filePath) {
return $False
}
}
class DocxValidator : Validator {
[bool] Validate([string] $filePath) {
try {
$tempFile = [System.IO.Path]::GetTempFileName() + ".zip"
Copy-Item $filePath -Destination $tempFile
$tempDirectory = ([System.IO.Path]::GetTempPath()).ToString() + "validator"
Expand-Archive -LiteralPath $tempFile -DestinationPath $tempDirectory -Force
Remove-Item -Path $tempDirectory -Recurse -Force
return $true
}
catch {
Write-Host "Failed to validate file $($filePath)"
}
return $false
}
}
function Get-Validator {
[OutputType([Validator])]
param([string] $ValidatorType)
switch ($ValidatorType) {
"xml" {
return [XmlValidator]::new()
}
"json" {
return [JsonValidator]::new()
}
"docx" {
return [DocxValidator]::new()
}
Default {
throw "invalid validator type"
}
}
}
Export-ModuleMember -Function Get-Validator
This is the unit test:
Get-Module Validation-Helper | Remove-Module -Force
$modulePath = Resolve-Path -Path "$($PSScriptRoot)\..\Validation-Helper\Validation-Helper.psm1"
Import-Module $modulePath
InModuleScope Validation-Helper {
Describe 'Validator for docx' {
Context 'when the document is valid' {
# arrange
BeforeAll {
Mock Write-Host { }
Mock Copy-Item { }
# this was another hint, to explicitly add the module scope here
Mock -ModuleName Validation-Helper Expand-Archive { } -Verifiable -ParameterFilter {
}
}
$tempFile = [System.IO.Path]::GetTempFileName()
$docxValidator = Get-Validator -ValidatorType "docx"
# act | assert
It 'returns true' {
$docxValidator.Validate($tempFile) | Should Be $true
}
}
}
}
The exception that I get in the catch branch of the Validate() method:
System.Management.Automation.MethodInvocationException: Exception calling ".ctor" with "3" argument(s): "Central Directory corrupt." ---> System.IO.InvalidDataException: Central Directory corrupt. ---> System.IO.IOException: An attempt was made to move the file pointer before the beginning of the file.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.FileStream.SeekCore(Int64 offset, SeekOrigin origin)
at System.IO.FileStream.Seek(Int64 offset, SeekOrigin origin)
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
--- End of inner exception stack trace ---
at System.IO.Compression.ZipArchive.ReadEndOfCentralDirectory()
at System.IO.Compression.ZipArchive.Init(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
at System.IO.Compression.ZipArchive..ctor(Stream stream, ZipArchiveMode mode, Boolean leaveOpen)
--- End of inner exception stack trace ---
at System.Management.Automation.DotNetAdapter.AuxiliaryConstructorInvoke(MethodInformation methodInformation, Object[] arguments, Object[] originalArguments)
at System.Management.Automation.DotNetAdapter.ConstructorInvokeDotNet(Type type, ConstructorInfo[] constructors, Object[] arguments)
at Microsoft.PowerShell.Commands.NewObjectCommand.CallConstructor(Type type, ConstructorInfo[] constructors, Object[] args)
Background: I'm currently working on a Powershell module, that shall verify if a Word document docx is corrupted. The idea is, that each docx document is basically a zip file. Therefore it should be possible to use any extract method to extract it - if no error during extraction occurs, the file is ok.