アサーション

アサーションは、実際の値が期待値に対応することを確認するために使用されます。これらは Tester\Assert クラスのメソッドです。

最も適切なアサーションを選択してください。Assert::same($a, $b)Assert::true($a === $b) よりも優れています。なぜなら、失敗した場合に意味のあるエラーメッセージが表示されるからです。2 番目のケースでは、false should be true のみが表示され、変数 $a$b の内容については何もわかりません。

ほとんどのアサーションには、オプションの $description パラメータを含めることもできます。これは、期待が失敗した場合にエラーメッセージに表示されます。

例では、エイリアスが作成されていることを前提としています。

use Tester\Assert;

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

$expected$actual と同一でなければなりません。PHP 演算子 === と同じです。

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

Assert::same() の逆。つまり、PHP 演算子 !== と同じです。

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

$expected$actual と同じでなければなりません。Assert::same() とは異なり、オブジェクトの同一性、配列内のキー ⇒ 値ペアの順序、およびわずかに異なる 10 進数は無視されます。これは $matchIdentity$matchOrder を設定することで変更できます。

次のケースは equal() の観点からは同じですが、same() の観点からは同じではありません。

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

ただし、注意してください。配列 [1, 2][2, 1] は同じではありません。なぜなら、キー ⇒ 値ペアではなく、値の順序のみが異なるからです。配列 [1, 2][0 => 1, 1 => 2] と書くこともでき、したがって [1 => 2, 0 => 1] が同じと見なされます。

さらに、$expected でいわゆる očekávání を使用できます。

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

Assert::equal() の逆。

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

$actual が文字列の場合、部分文字列 $needle を含まなければなりません。配列の場合、要素 $needle を含まなければなりません(厳密に比較されます)。

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

Assert::contains() の逆。

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

$actual は配列でなければならず、キー $needle を含まなければなりません。

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

$actual は配列でなければならず、キー $needle を含んではいけません。

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

$valuetrue でなければなりません。つまり、$value === true です。

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

$value は真でなければなりません。つまり、条件 if ($value) ... を満たします。

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

$valuefalse でなければなりません。つまり、$value === false です。

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

$value は偽でなければなりません。つまり、条件 if (!$value) ... を満たします。

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

$valuenull でなければなりません。つまり、$value === null です。

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

$valuenull であってはなりません。つまり、$value !== null です。

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

$value は Not a Number でなければなりません。NAN 値のテストには、Assert::nan() のみを使用してください。NAN 値は非常に特殊であり、アサーション Assert::same() または Assert::equal() は予期せず動作する可能性があります。

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

$value 内の要素の数は $count でなければなりません。つまり、count($value) === $count と同じです。

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

$value は指定された型でなければなりません。$type として文字列を使用できます。

  • array
  • list – ゼロから始まる昇順の数値キーでインデックス付けされた配列
  • bool
  • callable
  • float
  • int
  • null
  • object
  • resource
  • scalar
  • string
  • クラス名または直接オブジェクト。その場合、$value instanceof $type でなければなりません。

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

$callable を呼び出すと、クラス $class の例外がスローされなければなりません。$message を指定した場合、例外メッセージも パターンに一致 しなければならず、$code を指定した場合、コードも厳密に一致しなければなりません。

次のテストは、例外メッセージが一致しないため失敗します。

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

Assert::exception() はスローされた例外を返します。したがって、ネストされた例外もテストできます。

$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)

関数 $callable が期待されるエラー(つまり、警告、通知など)を生成したことを確認します。$type として、E_... 定数の 1 つ、たとえば E_WARNING を指定します。そして、$message を指定した場合、エラーメッセージも パターンに一致 しなければなりません。例:

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

コールバックが複数のエラーを生成する場合、それらすべてを正確な順序で期待する必要があります。その場合、$type に配列を渡します。

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

$type としてクラス名を指定した場合、Assert::exception() と同じように動作します。

Assert::noError (callable $callable)

関数 $callable が警告、エラー、または例外を生成しなかったことを確認します。他のアサーションがないコード片をテストする場合に役立ちます。

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

$actual はパターン $pattern に一致しなければなりません。2 つのバリアントのパターンを使用できます:正規表現またはワイルドカード。

$pattern として正規表現を渡す場合、その区切り文字として ~ または # を使用する必要があります。他の区切り文字はサポートされていません。たとえば、$var が 16 進数のみを含む必要がある場合のテスト:

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

2 番目のバリアントは通常の文字列比較に似ていますが、$pattern でさまざまなワイルドカードを使用できます。

  • %a% 1 つ以上の文字、改行文字を除く
  • %a?% ゼロ個以上の文字、改行文字を除く
  • %A% 1 つ以上の文字、改行文字を含む
  • %A?% ゼロ個以上の文字、改行文字を含む
  • %s% 1 つ以上の空白文字、改行文字を除く
  • %s?% ゼロ個以上の空白文字、改行文字を除く
  • %S% 1 つ以上の空白文字以外の文字
  • %S?% ゼロ個以上の空白文字以外の文字
  • %c% 任意の 1 文字、改行文字を除く
  • %d% 1 つ以上の数字
  • %d?% ゼロ個以上の数字
  • %i% 符号付き整数値
  • %f% 浮動小数点数
  • %h% 1 つ以上の 16 進数
  • %w% 1 つ以上の英数字
  • %% % 文字

例:

# 再び 16 進数のテスト
Assert::match('%h%', $var);

# ファイルパスと行番号の一般化
Assert::match('Error in file %a% on line %i%', $errorMessage);

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

アサーションは Assert::match() と同じですが、パターンはファイル $file から読み込まれます。これは、非常に長い文字列をテストする場合に役立ちます。テストファイルは明確なままです。

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

このアサーションは常に失敗します。時にはそれが役立ちます。オプションで、期待値と実際の値を指定することもできます。

期待値

非定数要素を持つより複雑な構造を比較したい場合、上記のアサーションでは不十分な場合があります。たとえば、新しいユーザーを作成し、その属性を配列として返すメソッドをテストします。パスワードハッシュの値はわかりませんが、それが 16 進文字列でなければならないことはわかっています。そして、別の要素については、それが DateTime オブジェクトでなければならないことしかわかりません。

これらの状況では、Assert::equal() および Assert::notEqual() メソッドの $expected パラメータ内で Tester\Expect を使用できます。これにより、構造を簡単に記述できます。

use Tester\Expect;

Assert::equal([
	'id' => Expect::type('int'),                   # 整数を期待します
	'username' => 'milo',
	'password' => Expect::match('%h%'),            # パターンに一致する文字列を期待します
	'created_at' => Expect::type(DateTime::class), # クラスのインスタンスを期待します
], User::create(123, 'milo', 'RandomPaSsWoRd'));

Expect を使用すると、Assert とほぼ同じアサーションを実行できます。つまり、メソッド Expect::same()Expect::match()Expect::count() などが利用可能です。さらに、それらを連鎖させることができます。

Expect::type(MyIterator::class)->andCount(5);  # MyIterator と要素数 5 を期待します

または、独自のアサーションハンドラを作成することもできます。

Expect::that(function ($value) {
	# 期待が失敗した場合に false を返します
});

失敗したアサーションの調査

アサーションが失敗すると、Tester は何が間違っているかを出力します。より複雑な構造を比較する場合、Tester は比較された値のダンプを作成し、それらを output ディレクトリに保存します。たとえば、架空のテスト Arrays.recursive.phpt が失敗した場合、ダンプは次のように保存されます。

app/
└── tests/
	├── output/
	│   ├── Arrays.recursive.actual    # 実際の値
	│   └── Arrays.recursive.expected  # 期待値
	│
	└── Arrays.recursive.phpt          # 失敗したテスト

ディレクトリ名は Tester\Dumper::$dumpDir を介して変更できます。