当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 使用数据驱动的 Pester 测试 PowerShell 掌握情况

作者:精品下载站 日期:2024-12-14 06:21:22 浏览:15 分类:玩电脑

使用数据驱动的 Pester 测试 PowerShell 掌握情况


我已经断断续续地使用 Pester 很长时间了。我一直致力于确保 PowerShell 代码的可靠性。在写完 Pester 书并提到我将在这篇博客文章中介绍的 Pester v4 中使用的一些方法之后,我了解到 Pester v5 让我的工作变得更加轻松。

您会看到,当您使用 Pester 构建测试时,您的选择就像 PowerShell 中的任何选项一样是无限的。您可以以一百万种不同的方式构建测试,因为您可以自由地在测试中编写您想要的任何 PowerShell。但这并不总是一件好事。您需要某种方法或构建它们的一般方法。这是我首选的方式;数据驱动的测试。

什么是数据驱动测试?

在典型的 Pester 测试套件中,您通常会为需要执行的每个断言创建一个 it 块。您创建一个 it 块来:

  • 断言脚本返回正确的输出
  • 断言脚本调用了正确的函数
  • 断言脚本在正确的位置创建一个文件。
  • …可能性是无止境

对于每种场景,您都可以创建一个带有名称的 it 块,并提供要传递给脚本以执行您正在测试的操作的所有参数。

例如:

describe 'some script' {
	it 'creates a thing given the parameters to do so' {
		./thing.ps1 -Create -Name 'xxx' | should -BeTrue
	}
	
	it 'sets a thing given the parameters to do so' {
		./thing.ps1 -Set -Name 'xxx' | should -BeTrue
	}
	
	it 'removes a thing given the parameters to do so' {
		./thing.ps1 -Remove -Name 'xxx' | should -BeTrue
	}
}

很公平。您已经定义了每个场景,提供了必要的参数,并断言脚本返回 true。这是创建测试的常见方法,但这种方法总是困扰我。当我可以将东西存储在数组中时,感觉就像我在不必要地重复代码。

事实证明,我可以!

在 Pester v5 中,您可以创建本质上是 foreach 循环的一部分的测试,将参数集一次性传递到块,并让 Pester 对每个参数集执行测试。

在上面的示例中,您对同一脚本使用了三个不同的参数集。这些集合可以在哈希表数组中定义。

$paramSets = @(
	@{
		Create = $true
		Name = 'xxx'
	}
	{
		Set = $true
		Name = 'xxx'
	}
	{
		Remove = $true
		Name = 'xxx'
	}
)

一旦它们全部存储在该数组中,您就可以使用 Pester v5 的 foreach 功能将它们“附加”到一个块,例如 it 块。

it 'whatever test name here' -ForEach $paramSets {
	## The parameter set is now represented as the current iteraction in the foreach loop
	$paramSet = $_
	 & "./thing.ps1" @paramSet | should -BeTrue
}

当您现在执行 Pester 测试时,它会将数组中设置的每个参数传递给 it 块,只需定义一个 it 块即可执行三个测试!效率更高。

保持 PowerShell 测试代码干燥

每个软件开发人员都知道 DRY 方法的概念。简而言之,就是不重复自己。这意味着尽可能不重复代码。为什么?为了可维护性。

想象一下需要创建 100 条数据库记录,您会看到如下代码:

New-Record -Table 'xxxx' -Fields @{ name = 'whatever1' }
New-Record -Table 'xxxx' -Fields @{ name = ' whatever2' }
New-Record -Table 'xxxx' -Fields @{ name = ' whatever3' }
New-Record -Table 'xxxx' -Fields @{ name = ' whatever4' }
New-Record -Table 'xxxx' -Fields @{ name = ' whatever5' }
New-Record -Table 'xxxx' -Fields @{ name = ' whatever6' }
## to 100

这 100 行代码可以很容易地减少到四行,从而简化了代码并使其更易于维护。

$whateverCount = 100
for ($i = 1; $i -lt $whateverCount; $i++) {
	New-Record -Table 'xxxx' -Fields @{ name = "whatever$i" }
}

它不仅简化了代码,而且只需更改一个数字就可以创建一百万条记录。这是干的。

那么为什么有些人要这样编写 Pester 测试呢?

describe 'some script' {
	it 'creates a thing given the parameters to do so' {
	
		./thing.ps1 -Create -Name 'xxx'
	
	}
	
	it 'sets a thing given the parameters to do so' {
		./thing.ps1 -Set -Name 'xxx'
	}
	
	it 'removes a thing given the parameters to do so' {
		./thing.ps1 -Remove -Name 'xxx'
	}
}

如果您是测试新手,或者确实阅读过 Pester 的文档,您会发现许多示例的结构都是这样的。这绝对没有问题!如果您正在为简单脚本构建少量测试,它就可以正常工作。但它总是困扰着我。

虽然不那么明显,但本质上你在做同样的事情;复制功能。但让 Pester 测试 DRY 并不像引入 for 循环和添加单个变量那么简单。您必须使用 Pester 的领域特定语言 (DSL) 来构建它们。

更好的测试覆盖率

编写测试,就像 PowerShell 代码一样,确实是一门艺术。有很多方法可以执行相同的操作,每种方法都有优点和缺点。当为大型 PowerShell 脚本编写测试时,您可能会疯狂地测试每一个……小……分钟……细节。或者,您可以走敏捷路线,创建一小组涵盖大多数情况的测试,然后在发现脚本在野外使用时如何失败时添加测试。

您如何在两者之间达成妥协?数据驱动测试!

通过数据驱动的测试,您可以通过提前定义数组中可能的每个参数集来定义调用脚本的每种单一方式。

如何进行 Pester 的数据驱动测试

现在您已经熟悉了数据驱动测试,现在让我们介绍一下我个人用来确保 PowerShell 代码的可管理测试覆盖率的方法。

  1. 在哈希表中定义强制参数。

    $mandatoryParameters = @{
        EndpointApiKey = (ConvertTo-SecureString -String 'apikeyhere' -AsPlainText -Force)
        PasswordName   = 'namehere'
        NewPassword    = (ConvertTo-SecureString -String 'passwordhere' -AsPlainText -Force)
    }

    如果您有强制性参数,您知道每次运行都必须将这些参数传递给脚本,因此请先定义它们。

  2. 创建一个哈希表数组,其中包括参数集哈希表测试名称。

    $mandatoryParameters = @{
        EndpointApiKey = (ConvertTo-SecureString -String 'apikeyhere' -AsPlainText -Force)
        PasswordName   = 'namehere'
        NewPassword    = (ConvertTo-SecureString -String 'passwordhere' -AsPlainText -Force)
    }
    
    $parameterSets = @(
        @{
            label         = 'all mandatory parameters'
            parameter_set = $mandatoryParameters
        }
        @{
            label         = 'specific EndpointUri'
            parameter_set = $mandatoryParameters + @{
                'EndpointUri' = 'https://endpointhere'
            }
        }
    )

    请注意,我只是将更多参数添加到 parameter_set 键中的参数集中,而不是复制强制参数。

  3. 创建适用于所有情况的主要上下文块。

    context 'Global' {
    	## do whatever in here that depends on the script
    }
  4. 为每种环境情况创建一个上下文块。

    context 'when the file exists' {
    
    }
    
    context 'when the file does not exist' {
    
    }
  5. 通过预先过滤掉传递到每个上下文的参数集来限制它们。

    context 'when the file exists' {
    	$ctxParameterSets = $parameterSets.where({ $_.parameter_set.ContainsKey('EndpointUri'') })
    }
  6. 创建表示您需要执行的任何测试的 it 块。

    it 'passes the expected URI to the API to update the password : <_.label>' -ForEach $parameterSets {
        & "$PSScriptRootthing.ps1" @parameter_set | should....
    }

    在 Pester v5 中,您可以在测试名称中插入一个字符串。我使用首先定义的数组中称为标签的键来注入该参数集的描述。

一旦我像这样构建了所有测试,我就可以简单地将参数集添加到数组中,该数组将自动运行我需要的所有测试!

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯