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

时间:2019-06-21 03:43:19

标签: c# powershell unit-testing cmdlet powershell-core

我写了simple PowerShell cmdlet in C#来炫耀我遇到的问题。可以随意克隆该存储库,或者将其分叉并使其正常工作并提交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

我正在跟踪在一些博客文章like this onethis one上找到的示例,但是我想他们在调用.Invoke()时没有这个问题。其他博客帖子like this one使用PsCmdletAssert类来.Invoke() cmdlet,但是PowerShellStandard.Library NuGet包中似乎不存在该类,所以我猜这不是PowerShell Core友好类。 Other blogs在每次测试执行时都创建一个新的运行空间和管道,但是同样,在使用PowerShellStandard库时,我似乎没有CreatePipeline()函数。

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

谢谢!


更新

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

当前PowerShellStandard.Library NuGet软件包的最新版本是5.1.0,因此希望此问题在将来的版本中得到解决。

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。通过将Microsoft.PowerShell.SDK安装到我的单元测试项目中,我能够解决此问题,随后我的arrayint clickCounter = 0; void onClick() { ++clickCounter; . . String src = "...\\Node_" + clickCounter + "\\...txt" } 调用开始正常工作。