在最后一个帖子中,我介绍了如何使用gherkin的裸基础。我与谈话 Joel Bennett. 关于gherkin的推特,他指出了他的更多例子 配置模块 。现在我已经和他们一起玩了几天,我决定分享我的发现是时候了。

这是在Gherkin上的3部分系列中的第二篇文章,其中我涵盖了高级功能。这些功能是建筑块,其给予大量功率。

  • 第1部分: 基本粗瓜介绍
  • 第2部分:先进的长春金色特征(这篇文章)
  • 第3部分:使用Gherkin(计划但未发布)

指数

快速复审

花点时间阅读 以前的帖子 . The idea is that you write a specification in common business speak consisting of several sentences. Each sentence is on its own line and starts with a keywords like Given,When,Then,But orAnd. This would be the .\copyitem.feature file.

Feature: You can copy one file

Scenario: The file exists, and the target folder exists
    Given we have a source file
    And we have a destination folder
    When we call Copy-Item
    Then we have a new file in the destination
    And the new file is the same as the original file

Then those are matched to the steps that validate the specification. The sentences are paired with a matching test. This would be the copyitem.Steps.ps1 file.

Given 'we have a source file' {
    mkdir testdrive:\source -ErrorAction SilentlyContinue
    Set-Content 'testdrive:\source\something.txt' -Value 'Data'
    'testdrive:\source\something.txt' | Should Exist
}

Given 'we have a destination folder' {
    mkdir testdrive:\target -ErrorAction SilentlyContinue
    'testdrive:\target' | Should Exist
}

When 'we call Copy-Item' {
    { Copy-Item testdrive:\source\something.txt testdrive:\target } | Should Not Throw
}

Then 'we have a new file in the destination' {
    'testdrive:\target\something.txt' | Should Exist
}

Then 'the new file is the same as the original file' {
    $primary = Get-FileHash testdrive:\target\something.txt
    $secondary = Get-FileHash testdrive:\source\something.txt
    $secondary.Hash | Should Be $primary.Hash
}

然后我们运行Invoke-gherkin以执行规范。

Invoke-Gherkin

这个想法很简单,但它有更多的东西。

标签

嫩香 has tag support at the feature and scenario level. You place them at the line above the scenario or feature on one line and prefix them with the @ sign.

@Functions @Milestone
Scenario: basic feature support
    Given we have public functions
    And we have a New-Node function

Then we can run those the scenarios that have the tag @Functions like this.

Invoke-Gherkin -Tag Functions

我们可以通过标签排除。

Invoke-Gherkin -ExcludeTag Milestone

这就像标签支持彼得用途。

背景情景

You can add a Background scenario to a Feature and it will get executed once before all the other scenarios in that Feature.

Feature: You can copy one file

Background: The file exists, and the target folder exists
    Given we have a source file
    And we have a destination folder

Scenario: Copy a single file
    When we call Copy-Item
    Then we have a new file in the destination
    And the new file is the same as the original file

它就像其他任何情况一样,但意图是识别预先要求或在该功能中为其他方案做一些常见的常用前工作。

efereCenario

In your script containing all your tests, you can specify a efereCenario script to run before each scenario.

 efereCenario  { 
    Set-Location TestDrive: 
}

This will change the working directory to the test drive before each scenario in case something changes it. We can also use tags to limit what scenario the efereCenario runs before.

 efereCenario  -Tags DataProcessing  {
    Set-Location TestDrive: 
}

By specifying a tag, this efereCenario script will only run for each scenario that has this same tag.

We also have AfterEachScenario, BeforeEachFeature and AfterEachFeature commands that work the same way. This lets you set up and tear down if the Background scenario just isn’t appropriate.

很多到一个

每个规范都与og体育匹配,您可以在多种方案中具有相同的规范。

Scenario: basic node support
    Given we have public functions
    And we have a New-Node function

Scenario: basic edge support
    Given we have public functions
    And we have a New-Edge function

In this example, the Given we have public functions in both scenarios would match the following test.

Given 'we have public functions' {
    "$psscriptroot\..\myModule\public\*.ps1" | Should Exist
}

这允许您对多种方案具有通用要求或语句,而无需创建更多og体育。

常用表达

我之前没有指出这一点,但og体育描述是正则表达式(正则表达式)。这使得为​​不同的规范描述重复使用og体育更容易。

让我们说我们在几个不同的位置使用此规范。

Given we have public functions
Given there are public functions

然后我们需要对每个og体育进行og体育。

Given 'we have public functions' {
    "$psscriptroot\..\MyModule\public\*.ps1" | Should Exist
}

Given 'there are public function' {
    "$psscriptroot\..\MyModule\public\*.ps1" | Should Exist
}

我们可以用正则表达式编写一个匹配两者而不是写作两个og体育。

Given '(we have|there are) public functions' {
    "$psscriptroot\..\MyModule\public\*.ps1" | Should Exist
}

这是一个真正方便的方法,让一个og体育匹配多个功能,在那里你正在谈论同样的东西,而是用不同的说法。

正则表达式匹配参数

Ghorkin的一个强大功能是我们可以在我们的字符串中使用命名匹配,并将其自动将其传递为参数。命名匹配是正则表达式规范的一部分。它允许您具有识别名称的子匹配。以下是使用名为RegEx模式的快速示例。

If("My Name is Kevin." -match 'My Name is (?<name>\S*).' )
{
    $matches.name
}

让我们从第一个示例中重新审视一个规范。

And the new file is the same as the original file

并将其重写为此以获取规范中列出的文件。

And the file .\target\something.txt is the same as .\source\something.txt

我们还希望参数化这些文件路径。

And 'the file (?<target>\S*) is the same as (?<source>\S*)' {
    param($Target,$Source)

    $primary = Get-FileHash $Target
    $secondary = Get-FileHash $Source
    $secondary.Hash | Should Be $primary.Hash
}

If we take a close look at that example; the named match (?<target>\S*) is passed in as $Target. My pattern of \S* is for consecutive characters that are not whitespace. We did the same thing for the second value. This would let us reuse that test for different files or in different specifications.

这是第二个例子。

Scenario: basic feature support
    Given we have public functions
    And we have a New-Node function
    And we have a New-Edge function
    And we have a New-Graph function
    And we have a New-Subgraph function

我们已经对公共职能进行了og体育。但现在我们需要一个og体育来覆盖每个功能。

Given 'we have a (?<name>\S*) function' {
    param($name)
    "$psscriptroot\..\MyModule\*\$name.ps1" | Should Exist
}

这是动态地从规范文本中拉动值。这给了我们很多灵活性。

正则表达式位置参数

我真的强调了最后一节中的命名参数,但这也适用于位置参数。表达式的顺序与参数的顺序匹配。所以这也是如此适用于这个例子

Then 'we have a (\S*) function' {
    param($functionName)
    "$psscriptroot\..\MyModule\*\$functionName.ps1" | Should Exist
}

我仍然推荐命名的比赛。

表格支持

我们可以在规范内定义一个表,并将通过它传递给我们的og体育。

Scenario: basic feature support
    Given we have these functions
    | Name       | Type    |
    | New-Node   | Public  |
    | New-Edge   | Public  |
    | Get-Indent | Private |

然后创建相应的og体育以使用该表。

Given 'We have these functions' {
    param($table)
    foreach($row in $table)
    {
        "$psscriptroot\..\MyModule\$($row.type)\$($row.name).ps1" | Should Exist
    }
}

使用表也允许您在其他规范中重用该og体育,而是使用不同的数据集。

Scenario: basic public functions
    Given we have these functions
    | Name       | Type    |
    | New-Node   | Public  |
    | New-Edge   | Public  |

Scenario: basic private functions
    Given we have these functions
    | Name       | Type    |
    | Get-Indent | Private |

In that example, the We have these functions would be run twice. Once with each table.

I called my parameter $table in that example, but I could have called it anything.

多线文本参数

那些以前的方法灵活且容易写规范的人。我们还有一个允许高级功能的选项。

这是一个多线文本参数。

Scenario: multi-line text example
    Given we have a multi-line parameter
        """
        first
        second
        third
        """

与上面的表格示例一样,这将传递到og体育,就像它是单个多线一样,就像这里的字符串一样。面对面值这可能不觉得它提供了很多。

哈希可参数

我们可以使用该多行参数来保存哈希表。

Scenario: Hashtable example
    Given we have a Hastable name key
        """
        Name  = " 凯文马奎特 "
        State = "California"
        """

然后我们必须将文本转换为我们的og体育中的哈希表。

Given "we have a Hastable name key" {
    param($Data)

    $hashtable = $Data | ConvertFrom-StringData
    $hashtable['Name'] | Should Not BeNullOrEmpty
}

使用拆分

我想指出,我们可以将这些哈希特拉可带到我们的功能。

Scenario: Splat function
    Given we have these values for New-Person
        """
        Name  = " 凯文马奎特 "
        State = "California"
        """

然后在og体育中使用它:

Given "we have these values" {
    param($Data)
    $hashtable = $Data | ConvertFrom-StringData
    New-Person @hashtable
}

这可能是提供从直接传递到og体育的规范中提供各种输入的强大方法。

JSON参数

我们可以采用该多线文本参数并将其视为JSON。

Scenario: JSON example
    Given we have a JSON name property
        """
        {
            "Name":" 凯文马奎特 "
        }
        """

然后我们在og体育中进行JSON转换。

Given "we have a JSON name property" {
    param($Data)

    $json = $Data | ConvertFrom-Json
    $json.Name | Should Not BeNullOrEmpty
}

这将允许我们从规范中将结构化数据变为我们的og体育。

scriptblocks.

The catch-all scenario is that we convert that text parameter to a ScriptBlock. If you would much rather put in PowerShell hashtable then we can do that.

Scenario: Splat function with script block
    Given we have these values for New-Person
        """
        @{
            Name  = " 凯文马奎特 "
            UserName = $env:UserName
        }
        """

然后在og体育中使用它:

Given "we have these values" {
    param($Data)

    $hashtable = Invoke-Expression $Data
    New-Person @hashtable
}

您可以将任何PowerShell ScriptBlock放入文本参数中。你应该这样做吗?不合时宜。您的代码实际上应该在og体育中而不是规范。

I do have to warn you that by using Invoke-Expression or even creating a ScriptBlock that you are turning a specification file into an executable file. You could consider limiting the commands that could be used in your specification. If you are interested in that, I have a better write up about 域特定语言 覆盖更多细节。

多次运行方案

我想重新审视我们在表格示例中使用的场景。具体示例的一个问题是如果og体育失败,则它将其整体失败。我们不知道是什么行造成了这个问题。如果我们为每个人运行一次og体育,这将是很好的。

We can do that by using a Scenario Outline and adding an Examples table. This will make the the whole scenario run once for each example.

Scenario Outline: functions are well made
    Given we have a <Function> function
    Then the <Function> should have comment based help

    Examples: public functions
    | Function |
    | New-Node |
    | New-Edge |

The <Function> gets replaced by the current value in the examples table. We would then match that with a regex in the test.

We can call that table Scenarios and it will work the same way as the Examples table. We can also specify more than one table for a given Scenario Outline.

Scenario Outline: functions are well made
    Given we have a <Function> function
    Then the <Function> should have comment based help

    Scenarios: public functions
    | Function |
    | New-Node |
    | New-Edge |

    Scenarios: private functions
    | Function   |
    | Get-Indent |

什么是第3部分?

我涵盖了很多高级功能,使Gherkin具有惊人的灵活性。在我的下一篇文章中,我计划向您展示如何将所有这些工作融为一体。到目前为止,我们已经看到每个og体育在隔离中工作,但我们可以将这些og体育串在一起。我们可以使用在一次og体育中收集的值来用于后面的og体育。这是我们将看到一切都在一起的地方。

  • 第3部分:使用Gherkin(计划但未发布)