Testes com Pester
LidoNesta aula, você aprenderá a usar o Pester, o framework de testes para PowerShell, desde sua instalação até a criação de testes com Describe/It, asserções e mocking. Ao final, você será capaz de escrever testes unitários e de integração para seus scripts, aumentando a confiabilidade do seu código.
O Pester é o framework de testes padrão para PowerShell, essencial para garantir a qualidade e a confiabilidade dos seus scripts e módulos. Com ele, você pode escrever testes unitários, de integração e até mesmo testes de aceitação, seguindo uma sintaxe simples e poderosa. Nesta aula, vamos explorar os conceitos fundamentais do Pester, desde a instalação até a criação de testes com mocks, para que você possa incorporar testes em seu fluxo de desenvolvimento.
O que é Pester
Pester é um framework de teste e mocking para PowerShell, inspirado em ferramentas como RSpec (Ruby) e Jasmine (JavaScript). Ele permite que você escreva testes de forma declarativa, usando blocos Describe e It, e fornece uma vasta gama de asserções para validar o comportamento do seu código. O Pester também oferece suporte a mocking, permitindo simular dependências externas, como cmdlets ou funções, para isolar o código em teste.
Com o Pester, você pode automatizar a verificação de que seus scripts funcionam como esperado, facilitando a detecção de regressões e a manutenção do código. Ele é amplamente utilizado na comunidade PowerShell e é incluído por padrão em muitas ferramentas de CI/CD, como Azure DevOps e GitHub Actions.
Para instalar o Pester, você pode usar o PowerShell Gallery. No Windows PowerShell 5.1, o Pester já vem instalado, mas é recomendável atualizar para a versão mais recente:
Install-Module -Name Pester -Force -SkipPublisherCheck
No PowerShell 7+, você pode instalar ou atualizar da mesma forma. Após a instalação, verifique a versão:
Get-Module Pester -ListAvailable | Select-Object Name, Version
Describe/It
Os blocos Describe e It são a espinha dorsal dos testes Pester. Describe agrupa um conjunto de testes relacionados, geralmente uma função ou um módulo. Ele pode conter blocos Context para organizar ainda mais os testes em cenários específicos. O bloco It define um teste individual, com uma descrição do que está sendo testado.
A estrutura básica de um teste é:
Describe "Nome do grupo de testes" {
It "Descrição do teste" {
# Código do teste
}
}
Dentro do bloco It, você executa o código que deseja testar e faz uma ou mais asserções. Por exemplo, vamos criar uma função simples e testá-la:
function Add-Numbers {
param($a, $b)
return $a + $b
}
Describe "Add-Numbers" {
It "Soma dois números corretamente" {
$result = Add-Numbers -a 2 -b 3
$result | Should -Be 5
}
}
Para executar os testes, você pode usar o comando Invoke-Pester. Se você salvar o código acima em um arquivo Add-Numbers.Tests.ps1 e executar Invoke-Pester no diretório, verá a saída mostrando que o teste passou.
É importante notar que o Pester usa o termo It para cada teste e Should para as asserções. A sintaxe é fluente e fácil de ler, tornando os testes quase como documentação executável.
Asserções
As asserções são as verificações que você faz em seus testes. O Pester oferece vários operadores de asserção por meio do comando Should. Os mais comuns são:
Should -Be: compara igualdade (equivalente a-eq).Should -BeExactly: compara igualdade exata (case-sensitive).Should -BeGreaterThan/Should -BeLessThan: comparações numéricas.Should -Contain: verifica se uma coleção contém um elemento.Should -Match: verifica se uma string corresponde a um padrão regex.Should -Throw: verifica se um comando lança uma exceção.
Exemplos de asserções:
Describe "Exemplos de asserções" {
It "Verifica igualdade" {
$value = 42
$value | Should -Be 42
}
It "Verifica que uma coleção contém um item" {
$array = @('a', 'b', 'c')
$array | Should -Contain 'b'
}
It "Verifica que uma string corresponde a um padrão" {
$name = 'John Doe'
$name | Should -Match '^John'
}
It "Verifica que um comando lança erro" {
{ throw "Erro" } | Should -Throw
}
}
Além dessas, há asserções para tipos, propriedades e até para coleções vazias. Você pode combinar asserções em um único teste para verificar múltiplas condições.
Mocking (visão geral)
Mocking é uma técnica que permite substituir partes do sistema por versões simuladas, para isolar a unidade de código que está sendo testada. No Pester, você pode usar o comando Mock para substituir cmdlets, funções ou até mesmo comandos nativos. Isso é útil quando você não quer depender de recursos externos, como serviços web, arquivos ou outros módulos, durante os testes.
A sintaxe básica do Mock é:
Mock NomeDoComando -MockWith { # comportamento simulado }
Por exemplo, suponha que você tenha uma função que chama Get-Process e você quer testar essa função sem depender dos processos reais do sistema:
function Get-RunningProcessCount {
$processes = Get-Process
return $processes.Count
}
Describe "Get-RunningProcessCount" {
It "Retorna o número de processos" {
Mock Get-Process -MockWith { return @(1, 2, 3) }
$count = Get-RunningProcessCount
$count | Should -Be 3
}
}
O Mock substitui o comando Get-Process dentro do escopo do teste, retornando uma lista fictícia. Isso permite que você teste a lógica da função sem depender do estado real do sistema.
Além disso, você pode verificar se um comando foi chamado com os parâmetros esperados usando Assert-MockCalled. Isso é útil para garantir que uma função dependente foi invocada corretamente.
Describe "Verificação de chamadas" {
It "Chama Get-Process uma vez" {
Mock Get-Process -MockWith { return @() }
Get-RunningProcessCount
Assert-MockCalled Get-Process -Times 1
}
}
O mocking é uma ferramenta poderosa para testes unitários, pois permite testar o comportamento da unidade em isolamento. No entanto, é importante não abusar, pois mocks em excesso podem esconder problemas de integração.
Boas Práticas e Observações Finais
Ao escrever testes com Pester, siga estas boas práticas para obter melhores resultados:
- Nomeie os testes de forma descritiva, para que fique claro o que está sendo verificado.
- Mantenha os testes independentes e isolados, evitando dependência de estado global.
- Use
Contextpara agrupar testes em cenários diferentes dentro de umDescribe. - Teste tanto os caminhos felizes quanto os casos de erro.
- Execute os testes com frequência, de preferência em um pipeline de CI.
- Use o mocking com moderação, apenas quando necessário para isolar a unidade.
Lembre-se de que o Pester é uma ferramenta essencial para o desenvolvimento profissional em PowerShell. Dominar seus conceitos básicos, como Describe/It, asserções e mocking, permitirá que você escreva código mais robusto e confiável.
Referências
- Pester Quick Start
- Pester Functions
- Pester Assertions
- Pester Mocking
- Microsoft Pester Module Documentation
- Pester GitHub Repository
Exercícios
- Exercício 1: Crie um teste Pester para uma função que calcula o fatorial de um número. A função deve ser definida no próprio teste. Teste com os valores 0, 1 e 5.
- Exercício 2: Escreva um teste que verifique se uma função retorna uma lista com o número esperado de itens. Use
Should -HaveCount. - Exercício 3: Crie um teste que use mocking para simular um cmdlet que acessa um serviço externo. Por exemplo, simule
Invoke-RestMethode teste uma função que chama esse cmdlet. - Exercício 4: Escreva um teste que verifique se um comando lança uma exceção quando um parâmetro é inválido. Use
Should -Throw. - Exercício 5: Use
Assert-MockCalledpara verificar que um comando foi chamado exatamente uma vez em um teste.
function Get-Factorial {
param($n)
if ($n -eq 0) { return 1 }
return $n * (Get-Factorial -n ($n - 1))
}
Describe "Get-Factorial" {
It "Calcula fatorial de 0" {
Get-Factorial -n 0 | Should -Be 1
}
It "Calcula fatorial de 1" {
Get-Factorial -n 1 | Should -Be 1
}
It "Calcula fatorial de 5" {
Get-Factorial -n 5 | Should -Be 120
}
}
function Get-Numbers {
return @(1, 2, 3)
}
Describe "Get-Numbers" {
It "Retorna 3 itens" {
$result = Get-Numbers
$result | Should -HaveCount 3
}
}
function Get-DataFromApi {
$response = Invoke-RestMethod -Uri "https://api.example.com/data"
return $response
}
Describe "Get-DataFromApi" {
It "Retorna dados simulados" {
Mock Invoke-RestMethod -MockWith { return @{name="John"} }
$data = Get-DataFromApi
$data.name | Should -Be "John"
}
}
function Test-Param {
param($value)
if ($value -lt 0) { throw "Valor não pode ser negativo" }
return $value
}
Describe "Test-Param" {
It "Lança exceção para valor negativo" {
{ Test-Param -value -1 } | Should -Throw
}
}
function Invoke-MyCommand {
Get-Process | Out-Null
}
Describe "Invoke-MyCommand" {
It "Chama Get-Process uma vez" {
Mock Get-Process -MockWith { return @() }
Invoke-MyCommand
Assert-MockCalled Get-Process -Times 1
}
}