Как выполнить модульное тестирование двоичного командлета PowerShell Core на C #

Я написал простой командлет PowerShell на C #, чтобы продемонстрировать проблему, с которой я сталкиваюсь. Не стесняйтесь клонировать репо или форкнуть его и заставить его работать и отправить PR, или просто посмотрите исходный код, чтобы точно узнать, что я делаю.

Я создал простой командлет PowerShell Core, используя пакет NuGet PowerShellStandard.Library. Я использую xUnit и пытаюсь запустить модульный тест для созданного мной командлета PowerShell. Проблема в том, что когда я вызываю метод .Invoke() экземпляра командлета, он выдает NullReferenceException.

Вот созданный мною командлет:

[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

Я следую примерам, которые я нашел в некоторых сообщениях в блогах, вроде этого и этот, но я думаю, у них нет этой проблемы при вызове .Invoke(). Другие сообщения в блоге, подобные этому, используйте PsCmdletAssert класс для .Invoke() командлета, но этот класс, похоже, не существует в PowerShellStandard.Library пакете NuGet, поэтому я предполагаю, что это не дружественный к PowerShell Core класс. Другие блоги создают новое пространство выполнения и конвейер для каждого выполнение теста, но опять же, у меня нет функции CreatePipeline() при использовании библиотеки PowerShellStandard.

Итак, мой вопрос: как я могу запустить тесты xUnit для моих PowerShell Core Cmdlet, которые я создаю на C #, чтобы убедиться, что они работают должным образом?

Заранее спасибо!


Обновлять

Использование версии System.Management.Automation.dll для .Net Framework не вызывает исключения при Invoke() запуске командлета, поэтому моя работа заключалась в том, чтобы определить проект модульного тестирования как проект .Net Framework, а не .Net Core. Это позволило мне провести модульное тестирование командлета, как и ожидалось, с использованием кода, показанного в этом сообщении. Командлет по-прежнему определен в проекте .Net Core и является кроссплатформенным, только модульные тесты - нет.

В настоящее время последней версией пакета PowerShellStandard.Library NuGet является 5.1.0, поэтому мы надеемся, что эта проблема будет решена в следующей версии.


person deadlydog    schedule 21.06.2019    source источник
comment
Я поискал в Google PsCmdletAssert.cs и нашел следующее: github.com/dfch/biz.dfch.CS.Testing/blob/develop/src/   -  person Jonathan Gilbert    schedule 25.06.2019
comment
Спасибо @JonathanGilbert. Похоже, здесь используется RunspaceConfiguration, который зависит от пакета Microsoft.PowerShell.5.ReferenceAssemblies NuGet, который не использует .Net Standard; для него требуется как минимум .Net Framework 4.6.1, поэтому он не совместим с разными платформами. Думаю, это еще не конец света, поскольку мне нужно было бы только включить ссылку в мой проект модульного тестирования, но я все же хотел бы найти действительно кроссплатформенное решение этой проблемы, чтобы я мог запускать модульные тесты на не- Машины / контейнеры Windows.   -  person deadlydog    schedule 26.06.2019
comment
Недавно MS опубликовала в блоге информацию о различных типах проектов PowerShell и о том, какие пакеты NuGet для них использовать: devblogs.microsoft.com/powershell/   -  person deadlydog    schedule 09.04.2020
comment
Я думал, что .NET 4.6.1 совместим с .NET Standard.   -  person Jonathan Gilbert    schedule 08.05.2020
comment
i.imgur.com/Qq0LbBQ.png   -  person Jonathan Gilbert    schedule 08.05.2020


Ответы (1)


У меня была такая же проблема. Мне удалось решить эту проблему, установив Microsoft.PowerShell.SDK в свое устройство. тестовый проект, после чего мои Cmdlet.Invoke() и Powershell.Create() вызовы начали работать правильно.

person Steve Rukuts    schedule 10.09.2019
comment
Спасибо, что указали мне правильное направление! Я также писал в блоге о процессе создания и тестирования командлетов PowerShell Core на C # по адресу blog.danskingdom.com/ - person deadlydog; 21.09.2019