如何在 C# 中对 PowerShell Core 二进制 cmdlet 进行单元测试
How to unit test a PowerShell Core binary cmdlet in C#
我写了一个 simple PowerShell cmdlet in C# 来展示我遇到的问题。随意克隆 repo,或者 fork 它并让它工作并提交 PR,或者只是查看源代码以了解我在做什么。
我使用 the PowerShellStandard.Library NuGet package 创建了一个简单的 PowerShell Core cmdlet。我正在使用 xUnit 并尝试 运行 针对我创建的 PowerShell cmdlet 进行单元测试。问题是当我调用 cmdlet 实例的 .Invoke()
方法时,它会抛出一个 NullReferenceException
.
这是我创建的 cmdlet:
[Cmdlet(VerbsCommon.Get, "RepeatedString")]
[OutputType(typeof(string))]
public class GetRepeatedStringCmdlet : Cmdlet
{
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
[Alias("Word")]
[ValidateNotNullOrEmpty()]
public string Phrase { get; set; }
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)]
[Alias("Repeat")]
public int NumberOfTimesToRepeatPhrase { get; set; }
protected override void ProcessRecord()
{
base.ProcessRecord();
var result = new StringBuilder();
for (int i = 0; i < NumberOfTimesToRepeatPhrase; i++)
{
result.Append(Phrase);
}
WriteObject(result.ToString());
}
}
这是我尝试进行的单元测试的示例 运行:
[Fact]
public void ShouldReturnThePhraseRepeatedTheCorrectNumberOfTimes()
{
// Arrange.
var phrase = "A test phrase.";
int numberOfTimesToRepeat = 3;
var cmdlet = new GetRepeatedStringCmdlet()
{
Phrase = phrase,
NumberOfTimesToRepeatPhrase = numberOfTimesToRepeat
};
var expectedResult = Enumerable.Repeat(phrase, numberOfTimesToRepeat);
// Act.
var enumerator = cmdlet.Invoke().GetEnumerator(); // NullReferenceException thrown here when calling .Invoke().
Assert.True(enumerator.MoveNext());
var results = enumerator.Current;
// Assert.
Assert.Equal(results, expectedResult);
}
当我在 PowerShell 中测试脚本时,它似乎工作正常:
ImportModule .\PowerShellCmdletInCSharpExample.dll
Get-RepeatedString -Phrase "Hello there" -NumberOfTimesToRepeatPhrase 3
Hello thereHello thereHello there
我正在按照我在某些博客 posts 上找到的示例进行操作,like this one and this one, but I guess they don't have this issue when calling .Invoke()
. Other blog posts, like this one, use a PsCmdletAssert
class to .Invoke()
the cmdlet, but that class does not seem to exist in the PowerShellStandard.Library
NuGet package, so I'm guessing it's a not a PowerShell Core friendly class. Other blogs 在每次测试执行时创建一个新的 运行 空间和管道,但同样,我不使用 PowerShellStandard 库时似乎没有 CreatePipeline()
功能。
所以我的问题是,我如何 运行 xUnit 测试我在 C# 中创建的 PowerShell Core Cmdlet
以验证它们是否按预期运行?
提前致谢!
更新
使用 System.Management.Automation.dll
的 .Net Framework 版本在 Invoke()
ing cmdlet 时不会引发异常,因此我的工作是将我的单元测试项目定义为 .Net Framework项目,而不是 .Net Core。这使我能够使用 post 中显示的代码按预期对 cmdlet 进行单元测试。该 cmdlet 仍然在 .Net Core 项目中定义并且是跨平台的,只有单元测试不是。
目前 PowerShellStandard.Library
NuGet 包的最新版本是 5.1.0,所以希望这个问题在未来的版本中得到解决。
我遇到了同样的问题。我能够通过将 Microsoft.PowerShell.SDK 安装到我的单元测试项目中来解决这个问题,于是我的 Cmdlet.Invoke()
和 Powershell.Create()
调用开始正常工作。
我写了一个 simple PowerShell cmdlet in C# 来展示我遇到的问题。随意克隆 repo,或者 fork 它并让它工作并提交 PR,或者只是查看源代码以了解我在做什么。
我使用 the PowerShellStandard.Library NuGet package 创建了一个简单的 PowerShell Core cmdlet。我正在使用 xUnit 并尝试 运行 针对我创建的 PowerShell cmdlet 进行单元测试。问题是当我调用 cmdlet 实例的 .Invoke()
方法时,它会抛出一个 NullReferenceException
.
这是我创建的 cmdlet:
[Cmdlet(VerbsCommon.Get, "RepeatedString")]
[OutputType(typeof(string))]
public class GetRepeatedStringCmdlet : Cmdlet
{
[Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
[Alias("Word")]
[ValidateNotNullOrEmpty()]
public string Phrase { get; set; }
[Parameter(Position = 1, Mandatory = true, ValueFromPipelineByPropertyName = true)]
[Alias("Repeat")]
public int NumberOfTimesToRepeatPhrase { get; set; }
protected override void ProcessRecord()
{
base.ProcessRecord();
var result = new StringBuilder();
for (int i = 0; i < NumberOfTimesToRepeatPhrase; i++)
{
result.Append(Phrase);
}
WriteObject(result.ToString());
}
}
这是我尝试进行的单元测试的示例 运行:
[Fact]
public void ShouldReturnThePhraseRepeatedTheCorrectNumberOfTimes()
{
// Arrange.
var phrase = "A test phrase.";
int numberOfTimesToRepeat = 3;
var cmdlet = new GetRepeatedStringCmdlet()
{
Phrase = phrase,
NumberOfTimesToRepeatPhrase = numberOfTimesToRepeat
};
var expectedResult = Enumerable.Repeat(phrase, numberOfTimesToRepeat);
// Act.
var enumerator = cmdlet.Invoke().GetEnumerator(); // NullReferenceException thrown here when calling .Invoke().
Assert.True(enumerator.MoveNext());
var results = enumerator.Current;
// Assert.
Assert.Equal(results, expectedResult);
}
当我在 PowerShell 中测试脚本时,它似乎工作正常:
ImportModule .\PowerShellCmdletInCSharpExample.dll
Get-RepeatedString -Phrase "Hello there" -NumberOfTimesToRepeatPhrase 3
Hello thereHello thereHello there
我正在按照我在某些博客 posts 上找到的示例进行操作,like this one and this one, but I guess they don't have this issue when calling .Invoke()
. Other blog posts, like this one, use a PsCmdletAssert
class to .Invoke()
the cmdlet, but that class does not seem to exist in the PowerShellStandard.Library
NuGet package, so I'm guessing it's a not a PowerShell Core friendly class. Other blogs 在每次测试执行时创建一个新的 运行 空间和管道,但同样,我不使用 PowerShellStandard 库时似乎没有 CreatePipeline()
功能。
所以我的问题是,我如何 运行 xUnit 测试我在 C# 中创建的 PowerShell Core Cmdlet
以验证它们是否按预期运行?
提前致谢!
更新
使用 System.Management.Automation.dll
的 .Net Framework 版本在 Invoke()
ing cmdlet 时不会引发异常,因此我的工作是将我的单元测试项目定义为 .Net Framework项目,而不是 .Net Core。这使我能够使用 post 中显示的代码按预期对 cmdlet 进行单元测试。该 cmdlet 仍然在 .Net Core 项目中定义并且是跨平台的,只有单元测试不是。
目前 PowerShellStandard.Library
NuGet 包的最新版本是 5.1.0,所以希望这个问题在未来的版本中得到解决。
我遇到了同样的问题。我能够通过将 Microsoft.PowerShell.SDK 安装到我的单元测试项目中来解决这个问题,于是我的 Cmdlet.Invoke()
和 Powershell.Create()
调用开始正常工作。