如何在 C# 中对 PowerShell Core 二进制 cmdlet 进行单元测试

dea*_*dog 2 c# powershell unit-testing cmdlet powershell-core

我用C#编写了一个简单的 PowerShell cmdlet来展示我遇到的问题。随意克隆 repo,或 fork 并使其工作并提交 PR,或者只是查看源代码以确切了解我在做什么。

我已经使用PowerShellStandard.Library NuGet 包创建了一个简单的 PowerShell Core cmdlet 。我正在使用 xUnit 并尝试针对我创建的 PowerShell cmdlet 运行单元测试。问题是当我调用.Invoke()cmdlet 实例的方法时,它抛出一个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());
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我尝试运行的单元测试示例:

[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);
}
Run Code Online (Sandbox Code Playgroud)

当我在 PowerShell 中测试脚本时,它似乎可以正常工作:

ImportModule .\PowerShellCmdletInCSharpExample.dll
Get-RepeatedString -Phrase "Hello there" -NumberOfTimesToRepeatPhrase 3
Hello thereHello thereHello there
Run Code Online (Sandbox Code Playgroud)

我正在遵循我在一些博客文章中找到的示例,例如 this onethis one,但我想它们在调用.Invoke(). 其他博客文章,比如这个,使用cmdlet 的一个PsCmdletAssert.Invoke(),但该类似乎不存在于PowerShellStandard.LibraryNuGet 包中,所以我猜它不是一个 PowerShell Core 友好类。其他博客在每次测试执行时都会创建一个新的运行空间和管道,但同样,我CreatePipeline()在使用 PowerShellStandard 库时似乎没有该功能。

所以我的问题是,如何针对我Cmdlet在 C# 中创建的PowerShell Core 运行 xUnit 测试以验证它们按预期运行?

提前致谢!


更新

使用 .Net Framework 版本的 cmdletSystem.Management.Automation.dll不会引发异常Invoke(),因此我的工作是将我的单元测试项目定义为 .Net Framework 项目,而不是 .Net Core。这使我能够使用本文中显示的代码按预期对 cmdlet 进行单元测试。cmdlet 仍然在 .Net Core 项目中定义并且是跨平台的,只有单元测试不是。

目前PowerShellStandard.LibraryNuGet 包的最新版本是 5.1.0,所以希望这个问题在未来的版本中得到解决。

Ste*_*uts 6

我遇到了同样的问题。我能够通过将Microsoft.PowerShell.SDK安装到我的单元测试项目中来解决这个问题,因此我的Cmdlet.Invoke()Powershell.Create()调用开始正常工作。

  • 感谢您为我指明了正确的方向!我还在博客中介绍了使用 C# 创建和测试 PowerShell Core cmdlet 的过程:https://blog.danskingdom.com/Create-and-test-PowerShell-Core-cmdlets-in-CSharp/ (2认同)