Προς το περιεχόμενο

PHP Mock Objects


Προτεινόμενες αναρτήσεις

Δημοσ.

Λοιπόν....  

Προσπαθώ να μάθώ γενικά περί Unit testing και έχοντας κοιτάξει διάφορα στο Internet έχω την εξής απορία.

 

Έστω ότι έχω την παρακάτω κλάση.

<?php

class Foo 
{
// bla bla

    public function myfunction()
    {
        
        // bla bla
        
        $result1 = $this->classA->makeAPICall($parametersA);

        // bla bla

        $result2 = $this->classB->makeAPICall($parametersB);

        return $this->process($result1, $result2);  

    }
// bla bla
}
?>

Οι κλάσεις Α , Β κάνουν calls προς τα APIs A και Β αντίστοιχα.

Πως μπορώ να κάνω Unit test την μέθοδο myfunction της κλάσης Foo για ολες τις πιθανές τιμές των result1 και result2 ;

 

Αν έχετε κάποιες πήγες (internet, βιβλία) που να τα εξηγούν όλα αυτά ακόμα καλύτερα !!!

 

Ευχαριστώ!

Δημοσ.

Αν τα $this->classA και $this->classB προέρχονται κατευθείαν από παραμέτρους του constructor, like this:

public function __construct(ClassA $classA, ClassB $classB)
{
    $this->classA = $classA;
    $this->classB = $classB;
}

τότε μέσα στο test θα κάνεις stub και τα δύο dependencies και θα καθορίσεις τις επιστρεφόμενες τιμές κάπως έτσι

$stubΑ = $this->createMock(ClassA::class);
$stubA->method('makeAPICall')->willReturn(ABC);

$stubB = $this->createMock(ClassB::class);
$stubB->method('makeAPICall')->willReturn(XYZ);

$foo = new Foo($stubA, $stubB);
// κλπ κλπ

Ενδεχομένως θα υπάρχουν κι άλλα expectations στα stubbed methods, αυτό είναι ανάλογα με το contract του κώδικά σου. Για να τα κάνεις όλα αυτά πιο εύκολα για πολλές τιμές των ABC και XYZ θα βάλεις στο test ένα data provider.

 

Αν τώρα δεν κάνεις dependency injection στον constructor τότε πολύ απλά η class Foo δεν είναι testable και θα πρέπει να κάνεις διάφορες νιντζιές για να κάνεις τη δουλειά (π.χ. αντικαθιστώντας τα $this->classX με κάποια τρικ) αν δε μπορείς να τη διορθώσεις.

 

Πάντως γενικά το "πώς θα κάνεις test" εξαρτάται σε τεράστιο βαθμό από το πόσο καλά είναι γραμμένες οι method σου και πόσο συνειδητοποιημένα είναι τα contracts που προσφέρουν (και μαθαίνει κανείς πολλά επί του θέματος προσπαθώντας να γράψει tests και βρίσκοντας τοίχο).

 

Στην προκειμένη ας πούμε δεν είναι φανερό τι ακριβώς θα τεστάρει το test για το οποίο μιλάμε. Θα τεστάρεις ας πούμε ότι καλώντας τη myfunction() εν τέλει καλείται η process() με τις συγκεκριμένες επιστρεφόμενες τιμές; Αν είναι έτσι τότε δεν έχει νόημα να δοκιμάσεις "όλες τις πιθανότητες" που λες. Θα τεστάρεις κάτι άλλο; Τι ακριβώς; Υπάρχουν "σωστά" test (που έχουν νόημα) και "λάθος" test (που δεν έχουν ή που είναι πολύ μπερδεμένα για να είναι χρήσιμα ως unit tests).

  • Like 1
Δημοσ.

Ευχαριστώ για την απάντηση! Ναι αυτό βασικά θέλω να κάνω. ΓΙα καποιες τιμές τελόσπάντων, των result1, result2 οτι έχω το αναμενόμενο αποτέλεσμα.

 

Κάτι άκομα, δεν υπάρχει τρόπος να κάνω mock ένα constant σε ένα τεστ ε;

(δηλαδή να αλλάξω την τιμή του ΜΟΝΟ για το τεστ , χωρίς να επηρεάσω τον υπόλοιπο κώδικα)

 

Όταν λέω constant εννοώ το παρακάτω

 

 

define("FOO_CONSTANT",     "something");

Δημοσ.

Κάτι άκομα, δεν υπάρχει τρόπος να κάνω mock ένα constant σε ένα τεστ ε;

(δηλαδή να αλλάξω την τιμή του ΜΟΝΟ για το τεστ , χωρίς να επηρεάσω τον υπόλοιπο κώδικα)

 

Όχι. Κώδικας που για να τεσταριστεί χρειάζεται να κάνεις κάτι τέτοιο == untestable κώδικας. Υπόψιν, δεν εννοώ πως δε γίνεται με κάποιο τρόπο να κανονίσεις να παίρνει διαφορετική τιμή το constant στα tests. Απλά ότι όταν έχεις φτάσει να πρέπει να το κάνεις αυτό έχεις ξεπεράσει το σημείο που θα έπρεπε οι τιμές αυτές να εισάγονται με dependency injection μέσα σε configuration objects.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...