难以模拟 Invoke-WebRequest 的 BasicHtmlWebResponseObject
Having difficultly mocking Invoke-WebRequest's BasicHtmlWebResponseObject
我正在尝试测试 PowerShell 函数的这一部分:
# post
$Response = Invoke-WebRequest -Method POST -Uri $Uri -Body $Body -ContentType 'application/xml'
# parse Response.Content; return as System.Xml.XmlDocument
[xml]$Response.Content
通过模拟 Invoke-WebRequest
返回的 BasicHtmlWebResponseObject
:
Mock Invoke-WebRequest {
$WebResponse = [System.Net.HttpWebResponse]::new()
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance').SetValue(
$WebResponse,
200,
'NonPublic,SetField',
$null,
(Get-Culture)
)
$Content = '<?xml version="1.0" encoding="UTF-8"?><response><control>failure<status></status></control><operation><result><status>failure</status></result></operation></response>'
$Response = [Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject]::new($WebResponse,$Content)
return $Response
}
此断言失败,因为我没有正确创建 HttpWebResponse
或 BasicHtmlWebResponseObject
:
It "returns the response's Content object" {
# act
$Content = Send-Request -Session $Session
# assert
Assert-MockCalled Invoke-WebRequest
$Content | Should -BeOfType [xml]
$Content.response.control.status | Should -Be 'success'
$Content.response.operation.result.status | Should -Be 'success'
}
** 编辑 **
我考虑过使用 New-MockObject
:
Mock Invoke-WebRequest {
$Response = New‐MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Response.Content = '<?xml version="1.0" encoding="...'
}
但是,Content
属性 是只读的。
** /编辑**
我错过了什么?
在 PowerShell Core 上这对我不起作用:
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance')
这就是为什么您的 Mock 没有返回您期望的结果。但是,该行确实适用于 Windows PowerShell。不确定 PSCore 上的正确等价物是什么,需要研究,但我认为在此期间我会帮助你做到这一点。
这个有效:
Mock Invoke-WebRequest {
$Response = New-MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Content = `
'<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
$Response | Add-Member -NotePropertyName Content -NotePropertyValue $Content -Force
$Response
}
一个稍微简单的替代方法可能是将您的 invoke-webrequest 包装在一个函数中,然后只是模拟它。例如
function Get-XmlFromUri
{
param( $Uri, $Method, $Body )
$Response = Invoke-WebRequest -Method $Method -Uri $Uri -Body $Body -ContentType 'application/xml’
[xml]$Response.Content
}
现在您可以模拟 Get-XmlFromUri 和 return 来自硬编码 xml 的 System.Xml.XmlDocument 对象,这比需要反射调用自旋的 BasicHtmlWebResponseObject 更容易创建向上。
Mock Get-XmlFromUri {
[xml] '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
}
或者,根据您的代码需要它与 BasicHtmlWebResponseObject 的相似程度,您可以 return 来自 invoke-webrequest 模拟的哈希表,它具有您需要的属性:
Mock Invoke-WebRequest {
new-object pscustomobject -property @{
Content = '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>’
}
}
(对代码格式表示歉意 - 目前凌晨 4 点抱着一个不太困的婴儿在 iPhone 上用手打字:-S)
我正在尝试测试 PowerShell 函数的这一部分:
# post
$Response = Invoke-WebRequest -Method POST -Uri $Uri -Body $Body -ContentType 'application/xml'
# parse Response.Content; return as System.Xml.XmlDocument
[xml]$Response.Content
通过模拟 Invoke-WebRequest
返回的 BasicHtmlWebResponseObject
:
Mock Invoke-WebRequest {
$WebResponse = [System.Net.HttpWebResponse]::new()
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance').SetValue(
$WebResponse,
200,
'NonPublic,SetField',
$null,
(Get-Culture)
)
$Content = '<?xml version="1.0" encoding="UTF-8"?><response><control>failure<status></status></control><operation><result><status>failure</status></result></operation></response>'
$Response = [Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject]::new($WebResponse,$Content)
return $Response
}
此断言失败,因为我没有正确创建 HttpWebResponse
或 BasicHtmlWebResponseObject
:
It "returns the response's Content object" {
# act
$Content = Send-Request -Session $Session
# assert
Assert-MockCalled Invoke-WebRequest
$Content | Should -BeOfType [xml]
$Content.response.control.status | Should -Be 'success'
$Content.response.operation.result.status | Should -Be 'success'
}
** 编辑 **
我考虑过使用 New-MockObject
:
Mock Invoke-WebRequest {
$Response = New‐MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Response.Content = '<?xml version="1.0" encoding="...'
}
但是,Content
属性 是只读的。
** /编辑**
我错过了什么?
在 PowerShell Core 上这对我不起作用:
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance')
这就是为什么您的 Mock 没有返回您期望的结果。但是,该行确实适用于 Windows PowerShell。不确定 PSCore 上的正确等价物是什么,需要研究,但我认为在此期间我会帮助你做到这一点。
这个有效:
Mock Invoke-WebRequest {
$Response = New-MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Content = `
'<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
$Response | Add-Member -NotePropertyName Content -NotePropertyValue $Content -Force
$Response
}
一个稍微简单的替代方法可能是将您的 invoke-webrequest 包装在一个函数中,然后只是模拟它。例如
function Get-XmlFromUri
{
param( $Uri, $Method, $Body )
$Response = Invoke-WebRequest -Method $Method -Uri $Uri -Body $Body -ContentType 'application/xml’
[xml]$Response.Content
}
现在您可以模拟 Get-XmlFromUri 和 return 来自硬编码 xml 的 System.Xml.XmlDocument 对象,这比需要反射调用自旋的 BasicHtmlWebResponseObject 更容易创建向上。
Mock Get-XmlFromUri {
[xml] '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
}
或者,根据您的代码需要它与 BasicHtmlWebResponseObject 的相似程度,您可以 return 来自 invoke-webrequest 模拟的哈希表,它具有您需要的属性:
Mock Invoke-WebRequest {
new-object pscustomobject -property @{
Content = '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>’
}
}
(对代码格式表示歉意 - 目前凌晨 4 点抱着一个不太困的婴儿在 iPhone 上用手打字:-S)