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

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

Δημοσ.

Καλησπέρες,

Όπως ερωτώ και στο stackoverflow έχω μια κλάση στην οποία έχω μια μέθοδο getToken η οποία εκκινεί ένα Session:

namespace PCMagas;
define("API_OAUTH_TOKEN_URL","https://api.dropboxapi.com/oauth2/token");

use \GuzzleHttp\Client; 
use \GuzzleHttp\RequestOptions;

class Dropbox
{
    /**
     * @param String $appid The Dropbox Application Id.
     * @param String $secret The dropbox Secret
     * @param Client $httpClient The interface used to consume the Dropbox Rest API
     */
    public function __construct($appId,$secret,Client $httpClient)
    {
        $this->appId=$appId;
        $this->secret=$secret;
        $this->httpClient=$httpClient;
    }

    /**
     * Common Logic for Handling Http Error
     * @param Integer $code
     * @throws Exception
     */
    private function httpErrorHandling($code)
    {
        switch($code){
            case 400:
                throw new Exception('Invalid HttpRequest to DropBoxApi');
            case 401:
                throw new Exception('Invalid Dropbox Token');
            case 403:
                throw new Exception('Access Denied');
            case 429:
                throw new Exception('Try again later (after a 10th cup of coffee)');
            case 409:
                throw new Exception('Api user provided error');
            //Treat all 500 error code (seems kinda ugly)
            case 500:
            case 501:
            case 502:
            case 503:
            case 504:
            case 505:
            case 506:
            case 507:
            case 508:
            case 510:
            case 511:
                throw new Exception('Internal Dropbox Error');
        }
    }

    /**
     * @param String $code
     * @return String
     * @throws InvalidArgumentException In case that the code is not correctly Provided.
     * @throws Exception if any error occured when token cannot be fetched
     */
    public function getToken($code)
    {
        //If code get token from code
        //Else get token from $session
        //Not satisfiable thows Esception
        session_start();
        if(!empty($_SESSION['token'])){
            return $_SESSION['token'];
        }

        if(empty($code)){
            throw new \InvalidArgumentException('Please provide a code fetched from Dropbox Athorization.');
        }

        if(empty($_SESSION['redirect_url'])){
            throw new \Exception('Cannot find the url that Dropbox Redirected From');
        }

        $response = $this->httpClient->request("POST",API_OAUTH_TOKEN_URL,[
            RequestOptions::FORM_PARAMS =>[
                'code'=>$code,
                'grant_type'=>'authorization_code',
                'redirect_uri'=>$_SESSION['redirect_url']
            ],
            RequestOptions::AUTH=>[$this->appId,$this->secret]
        ]);

        //Call method and let it blow up
        $this->httpErrorHandling($response->getStatusCode());

        $body=$response->getBody()->getContents();
        $body=json_decode($body,true);
        $_SESSION['token']=$body['access_token'];
        return $_SESSION['token'];
    }
}

Και προσπαθώ να την κάνω Unit test:

namespace PCMagas\Tests;

use PHPUnit\Framework\TestCase;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Client;

use PCMagas\Dropbox;

define('ERROR_CODES',[400,401,403,409,429,500,501,502,503,504,505,506,507,508,510,511]);
define('ERROR_CODE_LENGTH',count(ERROR_CODES));

final class DropBoxTest extends TestCase
{

    private function mockErrorGuzzle()
    {
        $responses=array_map(function($statusCode){
            return new Response($statusCode);
        },ERROR_CODES);
        $handler = new MockHandler($responses);
        $client = new Client(['handler'=>$handler]);
        return $client;
    }

    public function testHttpErrorOnTonenFetch()
    {
        $guzzle=$this->mockErrorGuzzle();
        $dropBox=new Dropbox("dummyappId","dummySecret",$guzzle);
        for($i=0;$i<ERROR_CODE_LENGTH;$i++) {
            $this->expectException(\Exception::class);
            $dropBox->getToken("dummyCode");
        }
    }
}

Όμως όταν πάω να εκτελέσω το unit test λαμβάνω το εξής σφάλμα:

There was 1 error:

1) PCMagas\Tests\DropBoxTest::testHttpErrorOnTonenFetch
session_start(): Cannot start session when headers already sent

/home/vagrant/code/src/PCMagas/Dropbox.php:84
/home/vagrant/code/tests/DropBoxTest.php:36

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

 

Μπορείτε να με βοηθήσετε στο πως να διαχειριστώ το σφάλμα αυτό;

Δημοσ.

Ναι όμως θα εκκινώ το session είτε καλώ την μέθοδο είτε όχι, πράγμα που δεν θέλω. Οι κλάσεις φορτώνονται με PSR-4 autoloading και ο php κώδικας δεν τρέχει εντός borwser.

Δημοσ.
13 ώρες πριν, PC_MAGAS είπε

Ναι όμως θα εκκινώ το session είτε καλώ την μέθοδο είτε όχι, πράγμα που δεν θέλω. Οι κλάσεις φορτώνονται με PSR-4 autoloading και ο php κώδικας δεν τρέχει εντός borwser.

Δεν ξέρω άλλη λύση εναλλακτικά μπορείς να βάλεις στις ρυθμίσεις το session_auto_start.

 

Δημοσ. (επεξεργασμένο)

Σκεύτικα εάν έκανα μια Adapter κλάση για το Session θα μπορούσα εύκολα να την κάνω mock, αλλά μετά πως τεστάρεις την κλάση αυτή;

 

Τελικά κατέληξα στο να κάνω adapt το Session σε μια δική μου κλάση όπως αναφέρω στο https://stackoverflow.com/a/55871054/4706711, το κακό είναι ότι για να τεσταριστεί ο Adapter σε όλες τις περιπτώσεις θέλει 3 κιλά κώδικα και internal webserber. Το καλό είναι ότι έχεις ελάχιστο Κώδικα μη-τεσταρισμένο (Τον Adapter του Session) και τεσταρισμένο logic (την λογική του Πάρε-δώσε με το Dropbox).

 

Άντε τώρα καλό Mutation Testing.

Επεξ/σία από PC_MAGAS

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

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

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

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

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

Σύνδεση

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

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