Assertions

As afirmações são usadas para afirmar que um valor real corresponde a um valor esperado. Eles são métodos do Tester\Assert.

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

A maioria das afirmações também pode ter um $description opcional que aparece na mensagem de erro se a expectativa falhar.

Os exemplos assumem que a seguinte classe está definida:

use Tester\Assert;

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

$expected deve ser o mesmo que $actual. É o mesmo que o operador de PHP ===.

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

Ao contrário de Assert::same(), então é o mesmo que o operador PHP !==.

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

$expected deve ser o mesmo que $actual. Ao contrário de Assert::same(), a identidade do objeto, a ordem dos pares de chaves ⇒ valor em arrays e números decimais marginalmente diferentes são ignorados, o que pode ser alterado através da configuração $matchIdentity e $matchOrder.

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

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

Entretanto, tenha cuidado, a matriz [1, 2] e [2, 1] não são iguais, porque apenas a ordem dos valores é diferente, não a chave ⇒ pares de valores. A matriz [1, 2] também pode ser escrito como [0 => 1, 1 => 2] e, portanto [1 => 2, 0 => 1] serão considerados iguais.

Você também pode usar as chamadas expectativas em $expected.

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

Oposto a Assert::equal().

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

Se $actual for um fio, ele deve conter o substrato $needle. Se for uma matriz, deve conter o elemento $needle (é comparado estritamente).

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

Oposto a Assert::contains().

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

$actual deve ser uma matriz e deve conter a chave $needle.

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

$actual deve ser uma matriz e não deve conter a chave $needle.

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

$value deve ser true, portanto $value === true.

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

$value deve ser verdadeira, portanto satisfaz a condição if ($value) ....

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

$value deve ser false, portanto $value === false.

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

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

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

$value deve ser null, portanto $value === null.

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

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

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

$value não deve ser um número. Use apenas o Assert::nan() para testes NAN. O valor do NAN é muito específico e as afirmações Assert::same() ou Assert::equal() podem se comportar de forma imprevisível.

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

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

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

$value deve ser de um determinado tipo. Como $type, podemos usar cordel:

  • array
  • list – matriz indexada em ordem ascendente de chaves numéricas a partir de zero
  • bool
  • callable
  • float
  • int
  • null
  • object
  • resource
  • scalar
  • string
  • nome da classe ou objeto deve então passar diretamente $value instanceof $type

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

Em $callable deve ser lançada uma exceção de instância $class. Se passarmos $message, a mensagem da exceção deve coincidir. E se passarmos $code, o código da exceção deve ser o mesmo.

Por exemplo, este teste falha 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',
);

O Assert::exception() retorna uma exceção lançada, para que você possa testar uma exceção aninhada.

$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 invocação $callable gera os erros esperados (ou seja, avisos, avisos, etc.). Como $type, especificamos uma das constantes E_..., por exemplo E_WARNING. E, se passar $message, a mensagem de erro também deve corresponder ao padrão. Por exemplo:

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

Se a ligação de retorno gera mais erros, devemos esperar todos eles na ordem exata. Neste caso, passamos a matriz em $type:

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

Se $type é nome de classe, esta afirmação se comporta da mesma forma que Assert::exception().

Assert::noError(callable $callable)

Verifica se a função $callable não lança nenhum aviso/notificação/erro ou exceção em PHP. É útil para testar um pedaço de código onde não há outra asserção.

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

$actual Devemos corresponder a $pattern. Podemos utilizar duas variantes de padrões: expressões regulares ou wildcards.

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

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

A outra variante é semelhante à comparação de cordas, mas podemos usar alguns chars selvagens em $pattern:

  • %a% um ou mais de qualquer coisa, exceto os caracteres de fim de linha
  • %a?% zero ou mais de qualquer coisa, exceto os caracteres de fim de linha
  • %A% um ou mais de qualquer coisa, incluindo os caracteres de fim de linha
  • %A?% zero ou mais de qualquer coisa, incluindo os caracteres de fim de linha
  • %s% um ou mais caracteres de espaço branco, exceto os caracteres de fim de linha
  • %s?% zero ou mais caracteres de espaço branco, exceto os caracteres de fim de linha
  • %S% um ou mais caracteres, exceto o espaço branco
  • %S?% zero ou mais caracteres, exceto para o espaço branco
  • %c% um único personagem de qualquer tipo (exceto para o final da linha)
  • %d% um ou mais dígitos
  • %d?% zero ou mais dígitos
  • %i% valor inteiro assinado
  • %f% número do ponto flutuante
  • %h% um ou mais dígitos do HEX
  • %w% um ou mais caracteres alfanuméricos
  • %% um % de caráter

Exemplos:

# Again, hexadecimal number test
Assert::match('%h%', $var);

# Generalized path to file and line number
Assert::match('Error in file %a% on line %i%', $errorMessage);

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

A afirmação é idêntica a Assert::match() mas o padrão é carregado a partir de $file. É útil para testes de cordas muito longas. Os arquivos de teste podem ser lidos.

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

Esta afirmação sempre falha. É apenas útil. Opcionalmente, podemos passar os valores esperados e reais.

Expectativas

Se quisermos comparar estruturas mais complexas com elementos não-constantes, as afirmações acima podem não ser suficientes. Por exemplo, testamos um método que cria um novo usuário e devolve seus atributos como uma matriz. Não sabemos o valor do hash da senha, mas sabemos que ela deve ser uma string hexadecimal. E a única coisa que sabemos sobre o próximo elemento é que ele deve ser um objeto DateTime.

Nestes casos, podemos usar o Tester\Expect dentro do parâmetro $expected dos métodos Assert::equal() e Assert::notEqual(), que podem ser usados para descrever facilmente a estrutura.

use Tester\Expect;

Assert::equal([
	'id' => Expect::type('int'),                   # we expect an integer
	'username' => 'milo',
	'password' => Expect::match('%h%'),            # we expect a string matching pattern
	'created_at' => Expect::type(DateTime::class), # we expect an instance of the class
], User::create(123, 'milo', 'RandomPaSsWoRd'));

Com Expect, podemos fazer quase as mesmas afirmações que com Assert. Portanto, temos métodos como Expect::same(), Expect::match(), Expect::count(), etc. Além disso, podemos encadeá-los como:

Expect::type(MyIterator::class)->andCount(5);  # we expect MyIterator and items count is 5

Ou, podemos escrever os próprios responsáveis pelas asserções.

Expect::that(function ($value) {
	# return false if expectation fails
});

Investigação de Assertions Failed

O Tester mostra onde está o erro quando uma asserção falha. Quando comparamos estruturas complexas, o Tester cria despejos de valores comparados e os salva no diretório output. Por exemplo, quando o teste imaginário Arrays.recursive.phpt falha, os lixões serão salvos da seguinte forma:

app/
└── tests/
	├── output/
	│   ├── Arrays.recursive.actual    # actual value
	│   └── Arrays.recursive.expected  # expected value
	│
	└── Arrays.recursive.phpt          # failing test

Podemos mudar o nome do diretório por Tester\Dumper::$dumpDir.