2013-02-19 17 views
12

Ich würde einen Test für Symfony2 mit FOSUserBundle schreiben.Symfony2 - Tests mit FOSUserBundle

Im Moment habe ich einige Wege ausprobiert und niemand funktioniert.

Ich brauche eine Funktion wie "createAuthClient".

Hier ist meine grundlegende Klasse. Ich poste es, weil Sie mein Problem besser verstehen konnten.

<?php 
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; 
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; 
use Symfony\Component\BrowserKit\Cookie; 

class WebTestMain extends WebTestCase 
{ 
    protected static $container; 

    static protected function createClient(array $options = array(), array $server = array()) 
    { 
     $client = parent::createClient($options, $server); 

     self::$container = self::$kernel->getContainer(); 

     return $client; 
    } 

    static function createAuthClient(array $options = array(), array $server = array()) 
    { 
     // see lines below with my tries 
    } 
} 

Erster Versuch:

if(static::$kernel === null) 
{ 
    static::$kernel = static::createKernel($options); 
    static::$kernel->boot(); 
} 
if(static::$container === null) 
{ 
    self::$container = self::$kernel->getContainer(); 
} 

$parameters = self::$container->getParameter('test'); 
$server = array_merge(array('HTTP_HOST' => $parameters['host'], 'HTTP_USER_AGENT' => $parameters['useragent']), $server); 

$client = self::createClient($options, $server); 

$userProvider = self::$container->get('fos_user.user_manager'); 
$user = $userProvider->findUserBy(array('id' => 1)); 
$client->getCookieJar()->set(new Cookie('MOCKSESSID', true)); 
$session = self::$kernel->getContainer()->get('session'); 
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles()); 
$client->getContainer()->get('security.context')->setToken($token); 
$session->set('_security_main', serialize($token)); 

return $client; 

Dann suchte ich und suchte ... Mein zweiter Versuch.

if(static::$kernel === null) 
{ 
    static::$kernel = static::createKernel($options); 
    static::$kernel->boot(); 
} 
if(static::$container === null) 
{ 
    self::$container = self::$kernel->getContainer(); 
} 

$parameters = self::$container->getParameter('test'); 
$server = array_merge(
    array(
     'HTTP_HOST' => $parameters['host'], 
     'HTTP_USER_AGENT' => $parameters['useragent'], 
     'PHP_AUTH_USER' => 'admin', 
     'PHP_AUTH_PW' => 'admin' 
    ), 
    $server 
); 
$client = static::createClient(array(), array()); 
$client->followRedirects(); 
return $client; 

Und hier ist mein letzter Versuch, bevor ich diese Frage posten ...

$client = self::createClient($options, $server); 

$parameters = self::$container->getParameter('test'); 
$server = array_merge(
    array(
     'HTTP_HOST' => $parameters['host'], 
     'HTTP_USER_AGENT' => $parameters['useragent'] 
    ), 
    $server 
); 

$client->setServerParameters($server); 

$usermanager = self::$container->get('fos_user.user_manager'); 
$testuser = $usermanager->createUser(); 
$testuser->setUsername('test'); 
$testuser->setEmail('[email protected]'); 
$testuser->setPlainPassword('test'); 
$usermanager->updateUser($testuser); 

return $client; 

Vielen Dank im Voraus.

Antwort

17

Der beste Weg, den ich mit einem authentifizierten Benutzer testen kann, besteht darin, einfach Ihre Anmeldeseite zu besuchen und das Formular mit Benutzername und Passwort, das Sie von einem Gerät geladen haben, zu senden. Dies mag langsam und umständlich erscheinen, wird aber testen, was der Benutzer tatsächlich tun wird. Sie können sogar Ihre eigene Methode erstellen, um sie schnell und einfach zu verwenden.

public function doLogin($username, $password) { 
    $crawler = $this->client->request('GET', '/login'); 
    $form = $crawler->selectButton('_submit')->form(array(
     '_username' => $username, 
     '_password' => $password, 
     ));  
    $this->client->submit($form); 

    $this->assertTrue($this->client->getResponse()->isRedirect()); 

    $crawler = $this->client->followRedirect(); 
} 
+0

Große Informationen. Vielen Dank! – PatrickB

+0

Hat mir geholfen :) Danke + 1 – Code

+1

@Michael: könntest du mir bitte sagen, wie man eingeloggten Benutzer verifiziert, denn wenn wir falsches Passwort als Umleitung eingeben passieren auch. und $ this-> assertTrue ($ this-> client-> getResponse() -> isRedirect()); Dies scheint Arbeit in beiden – Code

15

ein AbstractControllerTest erstellen und an einen autorisierten Client auf setUp() wie folgt erstellen:

<?php 
// ... 
use Symfony\Component\BrowserKit\Cookie; 

abstract class AbstractControllerTest extends WebTestCase 
{ 
    /** 
    * @var Client 
    */ 
    protected $client = null; 


    public function setUp() 
    { 
     $this->client = $this->createAuthorizedClient(); 
    } 

    /** 
    * @return Client 
    */ 
    protected function createAuthorizedClient() 
    { 
     $client = static::createClient(); 
     $container = $client->getContainer(); 

     $session = $container->get('session'); 
     /** @var $userManager \FOS\UserBundle\Doctrine\UserManager */ 
     $userManager = $container->get('fos_user.user_manager'); 
     /** @var $loginManager \FOS\UserBundle\Security\LoginManager */ 
     $loginManager = $container->get('fos_user.security.login_manager'); 
     $firewallName = $container->getParameter('fos_user.firewall_name'); 

     $user = $userManager->findUserBy(array('username' => 'REPLACE_WITH_YOUR_TEST_USERNAME')); 
     $loginManager->loginUser($firewallName, $user); 

     // save the login token into the session and put it in a cookie 
     $container->get('session')->set('_security_' . $firewallName, 
      serialize($container->get('security.context')->getToken())); 
     $container->get('session')->save(); 
     $client->getCookieJar()->set(new Cookie($session->getName(), $session->getId())); 

     return $client; 
    } 
} 

HINWEIS: Bitte, die Benutzername mit Ihrem Testbenutzernamen ersetzen.

Dann erweitert die AbstractControllerTest und verwenden Sie die globale $client Anfragen wie folgt zu machen:

class ControllerTest extends AbstractControllerTest 
{ 
    public function testIndexAction() 
    { 
     $crawler = $this->client->request('GET', '/admin/'); 

     $this->assertEquals(
      Response::HTTP_OK, 
      $this->client->getResponse()->getStatusCode() 
     ); 
    } 
} 

Diese Methode getestet und funktioniert gut

+0

@ k0pernikus Ich verwende in meinem Beispiel keinen Namespace, daher wird implizit globaler Namespace verwendet, der keine Statement-Verwendung erfordert. –

+1

Ich finde, dass Abhängigkeiten explizit implizite Konvention viele Male schlägt. (Die Tatsache, dass ich diesen Kommentar schreibe, sollte dies offensichtlich machen.) In meinem aktuellen Projekt habe ich eine Reihe von "Client" -Klassen aus verschiedenen Drittanbieter-Bundles. Ich musste schauen und testen, bis ich feststellte, dass 'Symfony \ Component \ BrowserKit \ Client' der richtige war. Ihre Antwort wäre, obwohl sie ein schönes Arbeitsbeispiel liefert, viel nützlicher, wenn sie Benutzungsanweisungen enthält. Ab sofort ist noch manuelle Arbeit zur Ermittlung der Lösung erforderlich. – k0pernikus

+0

@ k0pernikus ja, du hast einen Punkt :) –

Verwandte Themen