Behauptungen

Aassertions werden verwendet, um zu behaupten, dass ein tatsächlicher Wert mit einem erwarteten Wert übereinstimmt. Sie sind Methoden des Tester\Assert.

Wählen Sie die genauesten Behauptungen. Assert::same($a, $b) ist besser als Assert::true($a === $b), weil es bei Fehlern eine sinnvolle Fehlermeldung anzeigt. Im zweiten Fall erhalten wir nur false should be true und es sagt nichts über den Inhalt der Variablen $a und $b aus.

Die meisten Assertions können auch eine optionale $description haben, die in der Fehlermeldung erscheint, wenn die Erwartung fehlschlägt.

Beispiele nehmen an, dass der folgende Klassenalias definiert ist:

use Tester\Assert;

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

$expected muss mit $actual identisch sein. Er ist identisch mit dem PHP-Operator ===.

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

Das Gegenteil von Assert::same(), also dasselbe wie der PHP-Operator !==.

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

$expected muss mit $actual identisch sein. Im Gegensatz zu Assert::same() werden Objektidentität, Reihenfolge von Schlüsselpaaren ⇒ Wert in Arrays und geringfügig unterschiedliche Dezimalzahlen ignoriert, was durch Setzen von $matchIdentity und $matchOrder geändert werden kann.

Die folgenden Fälle sind aus der Sicht von equal() identisch, aber nicht für same():

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

Beachten Sie jedoch, dass das Array [1, 2] und [2, 1] sind nicht gleich, da sich nur die Reihenfolge der Werte unterscheidet, nicht aber die Schlüssel ⇒ Wertpaare. Das Array [1, 2] kann auch geschrieben werden als [0 => 1, 1 => 2] geschrieben werden und daher [1 => 2, 0 => 1] als gleich betrachtet werden.

Sie können auch die sogenannten Erwartungen in $expected verwenden.

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

Im Gegensatz zu Assert::equal().

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

Wenn $actual eine Zeichenkette ist, muss sie die Teilzeichenkette $needle enthalten. Wenn es sich um ein Array handelt, muss es das Element $needle enthalten (es wird streng verglichen).

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

Im Gegensatz zu Assert::contains().

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

$actual muss ein Array sein und den Schlüssel $needle enthalten.

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

$actual muss ein Array sein und darf den Schlüssel $needle nicht enthalten.

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

$value muss true sein, also $value === true.

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

$value muss wahrheitsgemäß sein, also erfüllt es die Bedingung if ($value) ....

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

$value muss false sein, also $value === false.

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

$value muss falsch sein, also erfüllt es die Bedingung if (!$value) ....

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

$value muss null sein, also $value === null.

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

$value darf nicht null sein, also $value !== null.

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

$value muss Not a Number sein. Verwenden Sie für NAN-Tests nur die Assert::nan(). Der NAN-Wert ist sehr spezifisch und die Assertions Assert::same() oder Assert::equal() können sich unvorhersehbar verhalten.

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

Die Anzahl der Elemente in $value muss $count sein. Also dasselbe wie count($value) === $count.

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

$value muss von einem bestimmten Typ sein. Als $type können wir String verwenden:

  • array
  • list – Array, das in aufsteigender Reihenfolge der numerischen Schlüssel von Null an indiziert ist
  • bool
  • callable
  • float
  • int
  • null
  • object
  • resource
  • scalar
  • string
  • Klassenname oder Objekt direkt, dann müssen $value instanceof $type

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

Beim Aufruf von $callable muss eine Ausnahme der Instanz $class ausgelöst werden. Wenn wir $message übergeben, muss die Nachricht der Ausnahme übereinstimmen. Und wenn wir $code übergeben, muss der Code der Ausnahme derselbe sein.

Dieser Test schlägt zum Beispiel fehl, weil die Meldung der Ausnahme nicht übereinstimmt:

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

Die Assert::exception() gibt eine ausgelöste Ausnahme zurück, so dass Sie eine verschachtelte Ausnahme testen können.

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

Überprüft, ob der $callable -Aufruf die erwarteten Fehler erzeugt (d.h. Warnungen, Hinweise usw.). Als $type geben wir eine der Konstanten E_... an, zum Beispiel E_WARNING. Und wenn wir $message übergeben, muss die Fehlermeldung auch dem Muster entsprechen. Zum Beispiel:

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

Wenn der Rückruf mehrere Fehler erzeugt, müssen wir alle in der genauen Reihenfolge erwarten. In diesem Fall übergeben wir das Array in $type:

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

Wenn $type ein Klassenname ist, verhält sich diese Assertion genauso wie Assert::exception().

Assert::noError (callable $callable)

Überprüft, dass die Funktion $callable keine PHP-Warnung/Hinweis/Fehler oder Ausnahme auslöst. Sie ist nützlich, um ein Stück Code zu testen, für das es keine andere Assertion gibt.

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

$actual muss mit $pattern übereinstimmen. Wir können zwei Varianten von Mustern verwenden: reguläre Ausdrücke oder Wildcards.

Wenn wir einen regulären Ausdruck als $pattern übergeben, müssen wir ~ or # verwenden, um ihn abzugrenzen. Andere Begrenzungszeichen werden nicht unterstützt. Zum Beispiel test, bei dem $var nur hexadezimale Ziffern enthalten darf:

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

Die andere Variante ähnelt dem Vergleich von Zeichenketten, aber wir können einige Platzhalterzeichen in $pattern verwenden:

  • %a% ein oder mehrere beliebige Zeichen außer den Zeilenendezeichen
  • %a?% null oder mehr von irgendetwas, außer den Zeilenendezeichen
  • %A% ein oder mehrere beliebige Zeichen einschließlich der Zeilenendezeichen
  • %A?% null oder mehr von irgendetwas, einschließlich der Zeilenendezeichen
  • %s% ein oder mehrere Leerzeichen mit Ausnahme der Zeilenendezeichen
  • %s?% keine oder mehrere Leerzeichen, ausgenommen Zeilenende-Zeichen
  • %S% ein oder mehrere Zeichen mit Ausnahme des Leerzeichens
  • %S?% keine oder mehrere Zeichen außer dem Leerzeichen
  • %c% ein einzelnes Zeichen beliebiger Art (außer dem Zeilenende)
  • %d% eine oder mehrere Ziffern
  • %d?% keine oder mehrere Ziffern
  • %i% vorzeichenbehafteter Integer-Wert
  • %f% Gleitkommazahl
  • %h% eine oder mehrere HEX-Ziffern
  • %w% ein oder mehrere alphanumerische Zeichen
  • %% ein %-Zeichen

Beispiele:

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

Die Assertion ist identisch mit Assert::match(), aber das Muster wird von $file geladen. Sie ist nützlich für das Testen sehr langer Strings. Die Testdatei ist lesbar.

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

Diese Behauptung schlägt immer fehl. Sie ist einfach praktisch. Wir können optional erwartete und tatsächliche Werte übergeben.

Erwartungen

Wenn wir komplexere Strukturen mit nicht konstanten Elementen vergleichen wollen, sind die obigen Aussagen möglicherweise nicht ausreichend. Wir testen zum Beispiel eine Methode, die einen neuen Benutzer erstellt und seine Attribute als Array zurückgibt. Wir kennen den Hashwert des Kennworts nicht, aber wir wissen, dass es eine hexadezimale Zeichenkette sein muss. Und das einzige, was wir über das nächste Element wissen, ist, dass es ein Objekt DateTime sein muss.

In diesen Fällen können wir Tester\Expect innerhalb des $expected -Parameters der Assert::equal() – und Assert::notEqual() -Methoden verwenden, mit denen sich die Struktur leicht beschreiben lässt.

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'));

Mit Expect können wir fast die gleichen Behauptungen aufstellen wie mit Assert. Wir haben also Methoden wie Expect::same(), Expect::match(), Expect::count(), usw. Darüber hinaus können wir sie wie folgt verketten:

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

Oder wir können eigene Assertion Handler schreiben.

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

Untersuchung fehlgeschlagener Assertions

Der Tester zeigt an, wo der Fehler liegt, wenn eine Assertion fehlschlägt. Wenn wir komplexe Strukturen vergleichen, erstellt der Tester Dumps der verglichenen Werte und speichert sie im Verzeichnis output. Wenn zum Beispiel der imaginäre Test Arrays.recursive.phpt fehlschlägt, werden die Dumps wie folgt gespeichert:

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

Wir können den Namen des Verzeichnisses mit Tester\Dumper::$dumpDir ändern.