Ισχυρισμοί
Οι ισχυρισμοί χρησιμοποιούνται για να επιβεβαιώσουν ότι η
πραγματική τιμή αντιστοιχεί στην αναμενόμενη τιμή. Πρόκειται για
μεθόδους της κλάσης Tester\Assert
.
Επιλέξτε τους καταλληλότερους ισχυρισμούς. Είναι καλύτερο το
Assert::same($a, $b)
από το Assert::true($a === $b)
, επειδή σε περίπτωση
αποτυχίας εμφανίζει ένα ουσιαστικό μήνυμα σφάλματος. Στη δεύτερη
περίπτωση, μόνο το false should be true
το οποίο δεν μας λέει τίποτα για
το περιεχόμενο των μεταβλητών $a
και $b
.
Οι περισσότεροι ισχυρισμοί μπορούν επίσης να έχουν μια προαιρετική
περιγραφή στην παράμετρο $description
, η οποία εμφανίζεται στο μήνυμα
σφάλματος εάν η προσδοκία αποτύχει.
Τα παραδείγματα προϋποθέτουν τη δημιουργία ενός alias:
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()
, αγνοείται η ταυτότητα των αντικειμένων, η σειρά των
ζευγών κλειδιού ⇒ τιμής στους πίνακες και οι οριακά διαφορετικοί
δεκαδικοί αριθμοί, κάτι που μπορεί να αλλάξει ρυθμίζοντας τα
$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
μπορούν να χρησιμοποιηθούν οι λεγόμενες Προσδοκίες.
Assert::notEqual ($expected, $actual, ?string $description=null)
Το αντίθετο του Assert::equal()
.
Assert::contains ($needle, string|array $actual, ?string $description=null)
Εάν το $actual
είναι string, πρέπει να περιέχει το substring $needle
.
Εάν είναι array, πρέπει να περιέχει το στοιχείο $needle
(συγκρίνεται
αυστηρά).
Assert::notContains ($needle, string|array $actual, ?string $description=null)
Το αντίθετο του Assert::contains()
.
Assert::hasKey (string|int $needle, array $actual, ?string $description=null)
Το $actual
πρέπει να είναι array και πρέπει να περιέχει το κλειδί
$needle
.
Assert::notHasKey (string|int $needle, array $actual, ?string $description=null)
Το $actual
πρέπει να είναι array και δεν πρέπει να περιέχει το κλειδί
$needle
.
Assert::true ($value, ?string $description=null)
Το $value
πρέπει να είναι true
, δηλαδή $value === true
.
Assert::truthy ($value, ?string $description=null)
Το $value
πρέπει να είναι αληθές (truthy), δηλαδή να ικανοποιεί τη
συνθήκη if ($value) ...
.
Assert::false ($value, ?string $description=null)
Το $value
πρέπει να είναι false
, δηλαδή $value === false
.
Assert::falsey ($value, ?string $description=null)
Το $value
πρέπει να είναι ψευδές (falsey), δηλαδή να ικανοποιεί τη
συνθήκη if (!$value) ...
.
Assert::null ($value, ?string $description=null)
Το $value
πρέπει να είναι null
, δηλαδή $value === null
.
Assert::notNull ($value, ?string $description=null)
Το $value
δεν πρέπει να είναι null
, δηλαδή $value !== null
.
Assert::nan ($value, ?string $description=null)
Το $value
πρέπει να είναι Not a Number. Για τον έλεγχο της τιμής NAN
χρησιμοποιείτε αποκλειστικά το Assert::nan()
. Η τιμή NAN είναι πολύ
συγκεκριμένη και οι assertions 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_...
, δηλαδή για παράδειγμα
E_WARNING
. Και αν αναφέρουμε $message
, πρέπει να αντιστοιχεί στο πρότυπο και το μήνυμα σφάλματος. Για
παράδειγμα:
Assert::error(
fn() => $i++,
E_NOTICE,
'Undefined variable: i',
);
Εάν το callback δημιουργήσει περισσότερα σφάλματα, πρέπει να τα
περιμένουμε όλα με την ακριβή σειρά. Σε αυτήν την περίπτωση, περνάμε
στο $type
έναν πίνακα:
Assert::error(function () {
$a++;
$b++;
}, [
[E_NOTICE, 'Undefined variable: a'],
[E_NOTICE, 'Undefined variable: b'],
]);
Εάν ως $type
αναφέρετε όνομα κλάσης, συμπεριφέρεται το
ίδιο με το Assert::exception()
.
Assert::noError (callable $callable)
Ελέγχει ότι η συνάρτηση $callable
δεν δημιούργησε καμία
προειδοποίηση, σφάλμα ή εξαίρεση. Είναι χρήσιμο για τον έλεγχο
κομματιών κώδικα όπου δεν υπάρχει καμία άλλη assertion.
Assert::match (string $pattern, $actual, ?string $description=null)
Το $actual
πρέπει να ταιριάζει με το πρότυπο $pattern
. Μπορούμε
να χρησιμοποιήσουμε δύο παραλλαγές προτύπων: κανονικές εκφράσεις ή
μπαλαντέρ.
Εάν ως $pattern
περάσουμε μια κανονική έκφραση, για τον οριοθέτησή
της πρέπει να χρησιμοποιήσουμε ~
ή #
, άλλοι οριοθέτες δεν
υποστηρίζονται. Για παράδειγμα, μια δοκιμή όπου το $var
πρέπει να
περιέχει μόνο δεκαεξαδικούς αριθμούς:
Assert::match('#^[0-9a-f]$#i', $var);
Η δεύτερη παραλλαγή είναι παρόμοια με τη συνήθη σύγκριση
συμβολοσειρών, αλλά στο $pattern
μπορούμε να χρησιμοποιήσουμε
διάφορους μπαλαντέρ:
%a%
ένας ή περισσότεροι χαρακτήρες, εκτός από τους χαρακτήρες τέλους γραμμής%a?%
κανένας ή περισσότεροι χαρακτήρες, εκτός από τους χαρακτήρες τέλους γραμμής%A%
ένας ή περισσότεροι χαρακτήρες, συμπεριλαμβανομένων των χαρακτήρων τέλους γραμμής%A?%
κανένας ή περισσότεροι χαρακτήρες, συμπεριλαμβανομένων των χαρακτήρων τέλους γραμμής%s%
ένας ή περισσότεροι λευκοί χαρακτήρες, εκτός από τους χαρακτήρες τέλους γραμμής%s?%
κανένας ή περισσότεροι λευκοί χαρακτήρες, εκτός από τους χαρακτήρες τέλους γραμμής%S%
ένας ή περισσότεροι χαρακτήρες, εκτός από τους λευκούς χαρακτήρες%S?%
κανένας ή περισσότεροι χαρακτήρες, εκτός από τους λευκούς χαρακτήρες%c%
οποιοσδήποτε ένας χαρακτήρας, εκτός από τον χαρακτήρα τέλους γραμμής%d%
ένα ή περισσότερα ψηφία%d?%
κανένα ή περισσότερα ψηφία%i%
προσημασμένη ακέραια τιμή%f%
αριθμός με δεκαδικό σημείο%h%
ένα ή περισσότερα δεκαεξαδικά ψηφία%w%
ένας ή περισσότεροι αλφαριθμητικοί χαρακτήρες%%
ο χαρακτήρας %
Παραδείγματα:
# Πάλι έλεγχος για δεκαεξαδικό αριθμό
Assert::match('%h%', $var);
# Γενίκευση της διαδρομής αρχείου και του αριθμού γραμμής
Assert::match('Error in file %a% on line %i%', $errorMessage);
Assert::matchFile (string $file, $actual, ?string $description=null)
Η assertion είναι ταυτόσημη με την Assert::match(), αλλά το
πρότυπο φορτώνεται από το αρχείο $file
. Αυτό είναι χρήσιμο για τον
έλεγχο πολύ μεγάλων συμβολοσειρών. Το αρχείο με τη δοκιμή παραμένει
ευανάγνωστο.
Assert::fail (string $message, $actual=null, $expected=null)
Αυτή η assertion αποτυγχάνει πάντα. Μερικές φορές αυτό είναι απλά χρήσιμο. Προαιρετικά, μπορούμε να αναφέρουμε και την αναμενόμενη και την πραγματική τιμή.
Προσδοκίες
Όταν θέλουμε να συγκρίνουμε πιο σύνθετες δομές με μη σταθερά
στοιχεία, οι παραπάνω assertions μπορεί να μην είναι επαρκείς. Για
παράδειγμα, ελέγχουμε μια μέθοδο που δημιουργεί έναν νέο χρήστη και
επιστρέφει τα χαρακτηριστικά του ως πίνακα. Την τιμή του hash του κωδικού
πρόσβασης δεν τη γνωρίζουμε, αλλά ξέρουμε ότι πρέπει να είναι μια
δεκαεξαδική συμβολοσειρά. Και για ένα άλλο στοιχείο ξέρουμε μόνο ότι
πρέπει να είναι ένα αντικείμενο DateTime
.
Σε αυτές τις καταστάσεις μπορούμε να χρησιμοποιήσουμε το
Tester\Expect
μέσα στην παράμετρο $expected
των μεθόδων
Assert::equal()
και Assert::notEqual()
, με τις οποίες μπορούμε εύκολα να
περιγράψουμε τη δομή.
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
μπορούμε να εκτελέσουμε σχεδόν τις ίδιες assertions όπως
με το Assert
. Δηλαδή, έχουμε στη διάθεσή μας τις μεθόδους
Expect::same()
, Expect::match()
, Expect::count()
κ.λπ. Επιπλέον,
μπορούμε να τις συνδέσουμε:
Expect::type(MyIterator::class)->andCount(5); # περιμένουμε MyIterator και αριθμό στοιχείων 5
Ή μπορούμε να γράψουμε τους δικούς μας handlers assertions.
Expect::that(function ($value) {
# επιστρέφουμε false, εάν η προσδοκία αποτύχει
});
Διερεύνηση λανθασμένων assertions
Όταν μια assertion αποτυγχάνει, ο Tester εκτυπώνει πού είναι το λάθος. Εάν
συγκρίνουμε πιο σύνθετες δομές, ο Tester δημιουργεί dumps των συγκρινόμενων
τιμών και τις αποθηκεύει στον κατάλογο output
. Για παράδειγμα, κατά
την αποτυχία της φανταστικής δοκιμής Arrays.recursive.phpt
, τα dumps θα
αποθηκευτούν ως εξής:
app/
└── tests/
├── output/
│ ├── Arrays.recursive.actual # πραγματική τιμή
│ └── Arrays.recursive.expected # αναμενόμενη τιμή
│
└── Arrays.recursive.phpt # αποτυχημένη δοκιμή
Το όνομα του καταλόγου μπορούμε να το αλλάξουμε μέσω του
Tester\Dumper::$dumpDir
.