Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mocking CimInstance does not work #1944

Closed
rifftual opened this issue May 14, 2021 · 4 comments
Closed

Mocking CimInstance does not work #1944

rifftual opened this issue May 14, 2021 · 4 comments
Milestone

Comments

@rifftual
Copy link
Contributor

General summary of the issue

A mock object of 'Microsoft.Management.Infrastructure.CimInstance' does not work. When trying to use the created object the following error is thrown: NullReferenceException: Object reference not set to an instance of an object.

Not sure if related, but see #345

Describe your environment

Pester version     : 5.1.1
PowerShell version : 5.1.18362.1474
OS version         : Microsoft Windows NT 10.0.18363.0

Steps to reproduce

$mock =  New-MockObject 'Microsoft.Management.Infrastructure.CimInstance'
Write-Host $mock

Expected Behavior

The mocked object works.

Current Behavior

The mocked object does not work.

@nohwnd
Copy link
Member

nohwnd commented May 14, 2021

This does not seem to be related to the linked issue. New-Mock object simply creates uninitialized instance of the given type. There is probably a property getter that relies on internal state that the object does not have. Please show the full error. And ideally stacktrace.

@rifftual
Copy link
Contributor Author

File contents

#Requires  -Version 5.1

Describe 'Test' {
    Describe 'foo' {
        It 'bar' {
            $fixture = New-MockObject 'Microsoft.Management.Infrastructure.CimInstance'
            Write-Host $fixture
        }
    }
}

Command

Invoke-Pester -Configuration @{ Run = @{ Path = 'test.ps1' };Output = @{ Verbosity = 'Detailed' } }

Starting discovery in 1 files.
Discovering in C:\Users\foo\source\repos\rmd-devops-core\test.ps1.
Found 1 tests. 6ms
Discovery finished in 11ms.

Running tests from 'C:\Users\foo\source\repos\rmd-devops-core\test.ps1'
Describing Test
 Describing foo
   [-] bar 5ms (3ms|2ms)
    at <ScriptBlock>, C:\Users\foo\source\repos\rmd-devops-core\test.ps1:7
    NullReferenceException: Object reference not set to an instance of an object.
Tests completed in 105ms
Tests Passed: 0, Failed: 1, Skipped: 0 NotRun: 0

@nohwnd nohwnd added this to the 5.3 milestone May 14, 2021
@nohwnd
Copy link
Member

nohwnd commented May 15, 2021

This is not Pester fault, internal state of the object is missing because you use intializer that does not set the internal state:

 Write-Host $fixture
PS> $error[0].exception.stacktrace
   at Microsoft.Management.Infrastructure.Internal.Data.CimPropertiesCollection.get_Item(String propertyName)
   at Microsoft.Management.Infrastructure.CimInstance.ToString()
   at Microsoft.PowerShell.Commands.WriteHostCommand.ProcessObject(Object o)
   at Microsoft.PowerShell.Commands.WriteHostCommand.ProcessObject(Object o)
   at Microsoft.PowerShell.Commands.WriteHostCommand.ProcessRecord()
   at System.Management.Automation.CommandProcessor.ProcessRecord()

Namely it is CimPropertiesCollection.get_Item that fails.

You can use one of the public constructors to get an instance of that type:

 [Microsoft.Management.Infrastructure.CimInstance]::new

OverloadDefinitions
-------------------
ciminstance new(ciminstance cimInstanceToClone)
ciminstance new(string className)
ciminstance new(string className, string namespaceName)
ciminstance new(cimclass cimClass)
PS> $c = [Microsoft.Management.Infrastructure.CimInstance]::new("abc")
PS> Write-Host $c
abc

@nohwnd nohwnd closed this as completed May 15, 2021
@fflaten
Copy link
Collaborator

fflaten commented May 15, 2021

The exception is caused by ToString() looking for an internal member, but you'd get the same with GetType() ++ as the object really is incomplete. Mocking a generic CimInstance by itself isn't very useful. You get the shell, but every CimInstance is by itself generic. It's first when you link it to a CIM-class and properties that it gives any value.

New-MockObject creates uninitialized instances of the named class, which won't work well out-of-the-box for types like this that rely on unknown internal state/properties.

You'd be better of creating a real ciminstance-object for the class (without saving it ofc) or you could use the CimInstance-constructor and generate what you need manually.

# Real CIM-object as reference
$realProc = Get-CimInstance Win32_Process | Select -first 1
$realProc

ProcessId Name                HandleCount WorkingSetSize VirtualSize
--------- ----                ----------- -------------- -----------
0         System Idle Process 0           8192           8192


$realProc.CimInstanceProperties.Count
45

# Mock
$procMock = [Microsoft.Management.Infrastructure.CimInstance]::new('Win32_Process','root/cimv2')
$procMock

ProcessId Name HandleCount WorkingSetSize VirtualSize
--------- ---- ----------- -------------- -----------


$procMock.CimInstanceProperties.Count
0

# No properties exists by default, only the extended aliasproperties from ETS in PowerShell
$procMock | Get-Member

   TypeName: Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_Process

Name                      MemberType     Definition
----                      ----------     ----------
Handles                   AliasProperty  Handles = Handlecount
ProcessName               AliasProperty  ProcessName = Name
VM                        AliasProperty  VM = VirtualSize
WS                        AliasProperty  WS = WorkingSetSize
#.... only base class stuff, none of the cim-properties you'd expect from Win32_Process

$name = [Microsoft.Management.Infrastructure.CimProperty]::Create('Name','MyProcess', [cimtype]::String, 'Property, ReadOnly')
$handlecount = [Microsoft.Management.Infrastructure.CimProperty]::Create('Handlecount', 123, [cimtype]::UInt32 , 'Property, ReadOnly')
$procMock.CimInstanceProperties.Add($name)
$procMock.CimInstanceProperties.Add($handlecount)

$procMock

ProcessId Name      HandleCount WorkingSetSize VirtualSize
--------- ----      ----------- -------------- -----------
          MyProcess 123


$procMock.CimInstanceProperties.Count
2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants