Nette Documentation Preview

syntax
Asserções
*********

.[perex]
As asserções são usadas para confirmar que o valor real corresponde ao valor esperado. São métodos da classe `Tester\Assert`.

Escolha as asserções mais adequadas. É melhor `Assert::same($a, $b)` do que `Assert::true($a === $b)`, porque em caso de falha exibe uma mensagem de erro significativa. No segundo caso, apenas `false should be true`, o que não nos diz nada sobre o conteúdo das variáveis `$a` e `$b`.

A maioria das asserções também pode ter uma descrição opcional no parâmetro `$description`, que será exibida na mensagem de erro se a expectativa falhar.

Os exemplos pressupõem a criação de um alias:

```php
use Tester\Assert;
```


Assert::same($expected, $actual, ?string $description=null) .[method]
---------------------------------------------------------------------
`$expected` deve ser idêntico a `$actual`. O mesmo que o operador PHP `===`.


Assert::notSame($expected, $actual, ?string $description=null) .[method]
------------------------------------------------------------------------
O oposto de `Assert::same()`, ou seja, o mesmo que o operador PHP `!==`.


Assert::equal($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false) .[method]
-------------------------------------------------------------------------------------------------------------------------
`$expected` deve ser igual a `$actual`. Ao contrário de `Assert::same()`, a identidade dos objetos, a ordem dos pares chave => valor em arrays e números decimais marginalmente diferentes são ignorados, o que pode ser alterado definindo `$matchIdentity` e `$matchOrder`.

Os seguintes casos são idênticos do ponto de vista de `equal()`, mas não de `same()`:

```php
Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
	['first' => 11, 'second' => 22],
	['second' => 22, 'first' => 11],
);
```

No entanto, atenção, os arrays `[1, 2]` e `[2, 1]` não são iguais, porque diferem apenas na ordem dos valores, não nos pares chave => valor. O array `[1, 2]` também pode ser escrito como `[0 => 1, 1 => 2]` e, portanto, `[1 => 2, 0 => 1]` será considerado igual.

Além disso, em `$expected` pode-se usar as chamadas [#expectations |#očekávání].


Assert::notEqual($expected, $actual, ?string $description=null) .[method]
-------------------------------------------------------------------------
O oposto de `Assert::equal()`.


Assert::contains($needle, string|array $actual, ?string $description=null) .[method]
------------------------------------------------------------------------------------
Se `$actual` for uma string, deve conter a substring `$needle`. Se for um array, deve conter o elemento `$needle` (comparado estritamente).


Assert::notContains($needle, string|array $actual, ?string $description=null) .[method]
---------------------------------------------------------------------------------------
O oposto de `Assert::contains()`.


Assert::hasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
--------------------------------------------------------------------------------------------------------
`$actual` deve ser um array e deve conter a chave `$needle`.


Assert::notHasKey(string|int $needle, array $actual, ?string $description=null) .[method]{data-version:2.4}
-----------------------------------------------------------------------------------------------------------
`$actual` deve ser um array e não deve conter a chave `$needle`.


Assert::true($value, ?string $description=null) .[method]
---------------------------------------------------------
`$value` deve ser `true`, ou seja, `$value === true`.


Assert::truthy($value, ?string $description=null) .[method]
-----------------------------------------------------------
`$value` deve ser verdadeiro, ou seja, satisfaz a condição `if ($value) ...`.


Assert::false($value, ?string $description=null) .[method]
----------------------------------------------------------
`$value` deve ser `false`, ou seja, `$value === false`.


Assert::falsey($value, ?string $description=null) .[method]
-----------------------------------------------------------
`$value` deve ser falso, ou seja, satisfaz a condição `if (!$value) ...`.


Assert::null($value, ?string $description=null) .[method]
---------------------------------------------------------
`$value` deve ser `null`, ou seja, `$value === null`.


Assert::notNull($value, ?string $description=null) .[method]
------------------------------------------------------------
`$value` não deve ser `null`, ou seja, `$value !== null`.


Assert::nan($value, ?string $description=null) .[method]
--------------------------------------------------------
`$value` deve ser Not a Number. Para testar valores NAN, use exclusivamente `Assert::nan()`. O valor NAN é muito específico e as asserções `Assert::same()` ou `Assert::equal()` podem funcionar inesperadamente.


Assert::count($count, Countable|array $value, ?string $description=null) .[method]
----------------------------------------------------------------------------------
O número de elementos em `$value` deve ser `$count`. Ou seja, o mesmo que `count($value) === $count`.


Assert::type(string|object $type, $value, ?string $description=null) .[method]
------------------------------------------------------------------------------
`$value` deve ser do tipo especificado. Como `$type`, podemos usar uma string:
- `array`
- `list` - array indexado por uma sequência crescente de chaves numéricas a partir de zero
- `bool`
- `callable`
- `float`
- `int`
- `null`
- `object`
- `resource`
- `scalar`
- `string`
- nome da classe ou diretamente o objeto, então `$value instanceof $type` deve ser verdadeiro


Assert::exception(callable $callable, string $class, ?string $message=null, $code=null) .[method]
-------------------------------------------------------------------------------------------------
Ao chamar `$callable`, uma exceção da classe `$class` deve ser lançada. Se especificarmos `$message`, a mensagem da exceção também deve [corresponder ao padrão|#assert-match] e, se especificarmos `$code`, os códigos também devem corresponder estritamente.

O seguinte teste falhará porque a mensagem da exceção não corresponde:

```php
Assert::exception(
	fn() => throw new App\InvalidValueException('Zero value'),
	App\InvalidValueException::class,
	'Value is to low',
);
```

`Assert::exception()` retorna a exceção lançada, permitindo testar também exceções aninhadas.

```php
$e = Assert::exception(
	fn() => throw new MyException('Something is wrong', 0, new RuntimeException),
	MyException::class,
	'Something is wrong',
);

Assert::type(RuntimeException::class, $e->getPrevious());
```


Assert::error(string $callable, int|string|array $type, ?string $message=null) .[method]
----------------------------------------------------------------------------------------
Verifica se a função `$callable` gerou os erros esperados (ou seja, avisos, notices, etc.). Como `$type`, especificamos uma das constantes `E_...`, por exemplo, `E_WARNING`. E se especificarmos `$message`, a mensagem de erro também deve [corresponder ao padrão|#assert-match]. Por exemplo:

```php
Assert::error(
	fn() => $i++,
	E_NOTICE,
	'Undefined variable: i',
);
```

Se o callback gerar múltiplos erros, devemos esperá-los todos na ordem exata. Nesse caso, passamos um array em `$type`:

```php
Assert::error(function () {
	$a++;
	$b++;
}, [
	[E_NOTICE, 'Undefined variable: a'],
	[E_NOTICE, 'Undefined variable: b'],
]);
```

.[note]
Se você especificar um nome de classe como `$type`, ele se comporta da mesma forma que `Assert::exception()`.


Assert::noError(callable $callable) .[method]
---------------------------------------------
Verifica se a função `$callable` não gerou nenhum aviso, erro ou exceção. É útil para testar pedaços de código onde não há outra asserção.


Assert::match(string $pattern, $actual, ?string $description=null) .[method]
----------------------------------------------------------------------------
`$actual` deve corresponder ao padrão `$pattern`. Podemos usar duas variantes de padrões: expressões regulares ou caracteres curinga.

Se passarmos uma expressão regular como `$pattern`, devemos usar `~` ou `#` para delimitá-la, outros delimitadores não são suportados. Por exemplo, um teste onde `$var` deve conter apenas dígitos hexadecimais:

```php
Assert::match('#^[0-9a-f]$#i', $var);
```

A segunda variante é semelhante à comparação normal de strings, mas em `$pattern` podemos usar vários caracteres curinga:

- `%a%` um ou mais caracteres, exceto caracteres de fim de linha
- `%a?%` nenhum ou mais caracteres, exceto caracteres de fim de linha
- `%A%` um ou mais caracteres, incluindo caracteres de fim de linha
- `%A?%` nenhum ou mais caracteres, incluindo caracteres de fim de linha
- `%s%` um ou mais espaços em branco, exceto caracteres de fim de linha
- `%s?%` nenhum ou mais espaços em branco, exceto caracteres de fim de linha
- `%S%` um ou mais caracteres, exceto espaços em branco
- `%S?%` nenhum ou mais caracteres, exceto espaços em branco
- `%c%` qualquer caractere único, exceto o caractere de fim de linha
- `%d%` um ou mais dígitos
- `%d?%` nenhum ou mais dígitos
- `%i%` valor inteiro com sinal
- `%f%` número de ponto flutuante
- `%h%` um ou mais dígitos hexadecimais
- `%w%` um ou mais caracteres alfanuméricos
- `%%` o caractere %

Exemplos:

```php
# Novamente, teste para número hexadecimal
Assert::match('%h%', $var);

# Generalização do caminho do arquivo e número da linha
Assert::match('Error in file %a% on line %i%', $errorMessage);
```


Assert::matchFile(string $file, $actual, ?string $description=null) .[method]
-----------------------------------------------------------------------------
A asserção é idêntica a [Assert::match() |#assert-match], mas o padrão é carregado do arquivo `$file`. Isso é útil para testar strings muito longas. O arquivo com o teste permanecerá claro.


Assert::fail(string $message, $actual=null, $expected=null) .[method]
---------------------------------------------------------------------
Esta asserção sempre falha. Às vezes, isso é útil. Opcionalmente, podemos especificar também o valor esperado e o atual.


Expectations
------------
Quando queremos comparar estruturas mais complexas com elementos não constantes, as asserções acima podem não ser suficientes. Por exemplo, testamos um método que cria um novo usuário e retorna seus atributos como um array. Não conhecemos o valor do hash da senha, mas sabemos que deve ser uma string hexadecimal. E sobre outro elemento, sabemos apenas que deve ser um objeto `DateTime`.

Nessas situações, podemos usar `Tester\Expect` dentro do parâmetro `$expected` dos métodos `Assert::equal()` e `Assert::notEqual()`, com os quais a estrutura pode ser facilmente descrita.

```php
use Tester\Expect;

Assert::equal([
	'id' => Expect::type('int'),                   # esperamos um número inteiro
	'username' => 'milo',
	'password' => Expect::match('%h%'),            # esperamos uma string que corresponda ao padrão
	'created_at' => Expect::type(DateTime::class), # esperamos uma instância da classe
], User::create(123, 'milo', 'RandomPaSsWoRd'));
```

Com `Expect`, podemos realizar quase as mesmas asserções que com `Assert`. Ou seja, temos à disposição os métodos `Expect::same()`, `Expect::match()`, `Expect::count()`, etc. Além disso, podemos encadeá-los:

```php
Expect::type(MyIterator::class)->andCount(5);  # esperamos MyIterator e número de elementos 5
```

Ou podemos escrever nossos próprios manipuladores de asserções.

```php
Expect::that(function ($value) {
	# retornamos false se a expectativa falhar
});
```


Investigando asserções falhas
-----------------------------
Quando uma asserção falha, o Tester exibe onde está o erro. Se compararmos estruturas mais complexas, o Tester criará dumps dos valores comparados e os salvará no diretório `output`. Por exemplo, em caso de falha do teste fictício `Arrays.recursive.phpt`, os dumps serão salvos da seguinte forma:

```
app/
└── tests/
	├── output/
	│   ├── Arrays.recursive.actual    # valor atual
	│   └── Arrays.recursive.expected  # valor esperado
	│
	└── Arrays.recursive.phpt          # teste falho
```

O nome do diretório pode ser alterado através de `Tester\Dumper::$dumpDir`.

Asserções

As asserções são usadas para confirmar que o valor real corresponde ao valor esperado. São métodos da classe Tester\Assert.

Escolha as asserções mais adequadas. É melhor Assert::same($a, $b) do que Assert::true($a === $b), porque em caso de falha exibe uma mensagem de erro significativa. No segundo caso, apenas false should be true, o que não nos diz nada sobre o conteúdo das variáveis $a e $b.

A maioria das asserções também pode ter uma descrição opcional no parâmetro $description, que será exibida na mensagem de erro se a expectativa falhar.

Os exemplos pressupõem a criação de um alias:

use Tester\Assert;

Assert::same($expected, $actual, ?string $description=null)

$expected deve ser idêntico a $actual. O mesmo que o operador PHP ===.

Assert::notSame($expected, $actual, ?string $description=null)

O oposto de Assert::same(), ou seja, o mesmo que o operador PHP !==.

Assert::equal($expected, $actual, ?string $description=null, bool $matchOrder=false, bool $matchIdentity=false)

$expected deve ser igual a $actual. Ao contrário de Assert::same(), a identidade dos objetos, a ordem dos pares chave ⇒ valor em arrays e números decimais marginalmente diferentes são ignorados, o que pode ser alterado definindo $matchIdentity e $matchOrder.

Os seguintes casos são idênticos do ponto de vista de equal(), mas não de same():

Assert::equal(0.3, 0.1 + 0.2);
Assert::equal($obj, clone $obj);
Assert::equal(
	['first' => 11, 'second' => 22],
	['second' => 22, 'first' => 11],
);

No entanto, atenção, os arrays [1, 2] e [2, 1] não são iguais, porque diferem apenas na ordem dos valores, não nos pares chave ⇒ valor. O array [1, 2] também pode ser escrito como [0 => 1, 1 => 2] e, portanto, [1 => 2, 0 => 1] será considerado igual.

Além disso, em $expected pode-se usar as chamadas #expectations.

Assert::notEqual($expected, $actual, ?string $description=null)

O oposto de Assert::equal().

Assert::contains($needle, string|array $actual, ?string $description=null)

Se $actual for uma string, deve conter a substring $needle. Se for um array, deve conter o elemento $needle (comparado estritamente).

Assert::notContains($needle, string|array $actual, ?string $description=null)

O oposto de Assert::contains().

Assert::hasKey(string|int $needle, array $actual, ?string $description=null)

$actual deve ser um array e deve conter a chave $needle.

Assert::notHasKey(string|int $needle, array $actual, ?string $description=null)

$actual deve ser um array e não deve conter a chave $needle.

Assert::true($value, ?string $description=null)

$value deve ser true, ou seja, $value === true.

Assert::truthy($value, ?string $description=null)

$value deve ser verdadeiro, ou seja, satisfaz a condição if ($value) ....

Assert::false($value, ?string $description=null)

$value deve ser false, ou seja, $value === false.

Assert::falsey($value, ?string $description=null)

$value deve ser falso, ou seja, satisfaz a condição if (!$value) ....

Assert::null($value, ?string $description=null)

$value deve ser null, ou seja, $value === null.

Assert::notNull($value, ?string $description=null)

$value não deve ser null, ou seja, $value !== null.

Assert::nan($value, ?string $description=null)

$value deve ser Not a Number. Para testar valores NAN, use exclusivamente Assert::nan(). O valor NAN é muito específico e as asserções Assert::same() ou Assert::equal() podem funcionar inesperadamente.

Assert::count($count, Countable|array $value, ?string $description=null)

O número de elementos em $value deve ser $count. Ou seja, o mesmo que count($value) === $count.

Assert::type(string|object $type, $value, ?string $description=null)

$value deve ser do tipo especificado. Como $type, podemos usar uma string:

  • array
  • list – array indexado por uma sequência crescente de chaves numéricas a partir de zero
  • bool
  • callable
  • float
  • int
  • null
  • object
  • resource
  • scalar
  • string
  • nome da classe ou diretamente o objeto, então $value instanceof $type deve ser verdadeiro

Assert::exception(callable $callable, string $class, ?string $message=null, $code=null)

Ao chamar $callable, uma exceção da classe $class deve ser lançada. Se especificarmos $message, a mensagem da exceção também deve corresponder ao padrão e, se especificarmos $code, os códigos também devem corresponder estritamente.

O seguinte teste falhará porque a mensagem da exceção não corresponde:

Assert::exception(
	fn() => throw new App\InvalidValueException('Zero value'),
	App\InvalidValueException::class,
	'Value is to low',
);

Assert::exception() retorna a exceção lançada, permitindo testar também exceções aninhadas.

$e = Assert::exception(
	fn() => throw new MyException('Something is wrong', 0, new RuntimeException),
	MyException::class,
	'Something is wrong',
);

Assert::type(RuntimeException::class, $e->getPrevious());

Assert::error(string $callable, int|string|array $type, ?string $message=null)

Verifica se a função $callable gerou os erros esperados (ou seja, avisos, notices, etc.). Como $type, especificamos uma das constantes E_..., por exemplo, E_WARNING. E se especificarmos $message, a mensagem de erro também deve corresponder ao padrão. Por exemplo:

Assert::error(
	fn() => $i++,
	E_NOTICE,
	'Undefined variable: i',
);

Se o callback gerar múltiplos erros, devemos esperá-los todos na ordem exata. Nesse caso, passamos um array em $type:

Assert::error(function () {
	$a++;
	$b++;
}, [
	[E_NOTICE, 'Undefined variable: a'],
	[E_NOTICE, 'Undefined variable: b'],
]);

Se você especificar um nome de classe como $type, ele se comporta da mesma forma que Assert::exception().

Assert::noError(callable $callable)

Verifica se a função $callable não gerou nenhum aviso, erro ou exceção. É útil para testar pedaços de código onde não há outra asserção.

Assert::match(string $pattern, $actual, ?string $description=null)

$actual deve corresponder ao padrão $pattern. Podemos usar duas variantes de padrões: expressões regulares ou caracteres curinga.

Se passarmos uma expressão regular como $pattern, devemos usar ~ ou # para delimitá-la, outros delimitadores não são suportados. Por exemplo, um teste onde $var deve conter apenas dígitos hexadecimais:

Assert::match('#^[0-9a-f]$#i', $var);

A segunda variante é semelhante à comparação normal de strings, mas em $pattern podemos usar vários caracteres curinga:

  • %a% um ou mais caracteres, exceto caracteres de fim de linha
  • %a?% nenhum ou mais caracteres, exceto caracteres de fim de linha
  • %A% um ou mais caracteres, incluindo caracteres de fim de linha
  • %A?% nenhum ou mais caracteres, incluindo caracteres de fim de linha
  • %s% um ou mais espaços em branco, exceto caracteres de fim de linha
  • %s?% nenhum ou mais espaços em branco, exceto caracteres de fim de linha
  • %S% um ou mais caracteres, exceto espaços em branco
  • %S?% nenhum ou mais caracteres, exceto espaços em branco
  • %c% qualquer caractere único, exceto o caractere de fim de linha
  • %d% um ou mais dígitos
  • %d?% nenhum ou mais dígitos
  • %i% valor inteiro com sinal
  • %f% número de ponto flutuante
  • %h% um ou mais dígitos hexadecimais
  • %w% um ou mais caracteres alfanuméricos
  • %% o caractere %

Exemplos:

# Novamente, teste para número hexadecimal
Assert::match('%h%', $var);

# Generalização do caminho do arquivo e número da linha
Assert::match('Error in file %a% on line %i%', $errorMessage);

Assert::matchFile(string $file, $actual, ?string $description=null)

A asserção é idêntica a Assert::match(), mas o padrão é carregado do arquivo $file. Isso é útil para testar strings muito longas. O arquivo com o teste permanecerá claro.

Assert::fail(string $message, $actual=null, $expected=null)

Esta asserção sempre falha. Às vezes, isso é útil. Opcionalmente, podemos especificar também o valor esperado e o atual.

Expectations

Quando queremos comparar estruturas mais complexas com elementos não constantes, as asserções acima podem não ser suficientes. Por exemplo, testamos um método que cria um novo usuário e retorna seus atributos como um array. Não conhecemos o valor do hash da senha, mas sabemos que deve ser uma string hexadecimal. E sobre outro elemento, sabemos apenas que deve ser um objeto DateTime.

Nessas situações, podemos usar Tester\Expect dentro do parâmetro $expected dos métodos Assert::equal() e Assert::notEqual(), com os quais a estrutura pode ser facilmente descrita.

use Tester\Expect;

Assert::equal([
	'id' => Expect::type('int'),                   # esperamos um número inteiro
	'username' => 'milo',
	'password' => Expect::match('%h%'),            # esperamos uma string que corresponda ao padrão
	'created_at' => Expect::type(DateTime::class), # esperamos uma instância da classe
], User::create(123, 'milo', 'RandomPaSsWoRd'));

Com Expect, podemos realizar quase as mesmas asserções que com Assert. Ou seja, temos à disposição os métodos Expect::same(), Expect::match(), Expect::count(), etc. Além disso, podemos encadeá-los:

Expect::type(MyIterator::class)->andCount(5);  # esperamos MyIterator e número de elementos 5

Ou podemos escrever nossos próprios manipuladores de asserções.

Expect::that(function ($value) {
	# retornamos false se a expectativa falhar
});

Investigando asserções falhas

Quando uma asserção falha, o Tester exibe onde está o erro. Se compararmos estruturas mais complexas, o Tester criará dumps dos valores comparados e os salvará no diretório output. Por exemplo, em caso de falha do teste fictício Arrays.recursive.phpt, os dumps serão salvos da seguinte forma:

app/
└── tests/
	├── output/
	│   ├── Arrays.recursive.actual    # valor atual
	│   └── Arrays.recursive.expected  # valor esperado
	│
	└── Arrays.recursive.phpt          # teste falho

O nome do diretório pode ser alterado através de Tester\Dumper::$dumpDir.