Fixture con contenitore di servizi nei test funzionali

A volte può essere utile avere a disposizione il contenitore di servizi nelle fixture usate nei test funzionali. Un caso tipico è l’uso di FOSUserBundle, che mette a disposizione un servizio UserManager per creare utenti, utilizzabile quindi anche per crearli all’interno delle fixture.
Purtroppo la documentazione a riguardo è alquanto avara di informazioni, per cui condivido qui questa soluzione, mostrando un esempio.
Ecco un possibile file di fixture per gli utenti:

<?php
 
namespace Acme\PippoBundle\DataFixtures\ORM;
 
 
use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
 
class LoadUserData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{
    private $container;
 
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }
 
    public function load(ObjectManager $manager)
    {
        $userManager = $this->container->get('fos_user.user_manager');
 
        $user1 = $userManager->createUser();
        $user1
            ->setUsername('pippo')
            ->setEmail('pippo@example.org')
            ->setFirstName('Mallo')
            ->setLastName('Di Noce')
            ->setBirthday(new \DateTime('1977-07-07'))
            ->setEnabled(true)
            ->setPlainPassword('mallodinoce')
        ;
        $userManager->updateUser($user1, false);
        $manager->persist($user1);
        $this->addReference('user1', $user1);
 
        $manager->flush();
    }
 
    public function getOrder()
    {
        return 1;
    }
}

Questa fixture si può usare in un test in questo modo:

<?php
 
namespace Acme\PippoBundle\Tests\Controller;
 
use Acme\PippoBundle\DataFixtures\ORM\LoadUserData;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader as Loader; // il trucco è qui..
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase
 
class DefaultControllerTest extends WebTestCase
{
    public function setUp()
    {
        $kernel = static::createKernel();
        $kernel->boot();
        $container = $kernel->getContainer();
        $loader = new Loader($container);  // ... e qui
        $loader->addFixture(new LoadUserData);
        $purger = new ORMPurger();
        $executor = new ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    } 
 
    public function testIndex()
    {
        $client = static::createClient();
        $crawler = $client->request('GET', '/');
        $this->assertTrue($client->getResponse()->isSuccessful());
    }
}

Velocizzare i test usando un RAM Disk

Dato che la RAM costa relativamente poco e il tempo invece è merce rara, mi pare una buona idea “investire” un po’ di RAM per risparmiare tempo. Se lavorate con una suite di test automatici probabilmente questa girerà decine di volte al giorno (forse addirittura all’ora) facendo una serie di operazioni su disco che, probabilmente, avranno un peso significativo sul tempo di esecuzione finale. Montando una porzione di RAM e utilizzandola come FS si può velocizzare l’esecuzione dei test.

Continue reading “Velocizzare i test usando un RAM Disk”

task con progress bar

A volte può capitare di dover eseguire dei task che durano diversi minuti, per esempio per delle importazioni o per delle conversioni di grandi quantità di dati. In questi casi può essere molto utile avere nel terminale una barra di progressione, che indichi le quantità dei dati già lavorati e ancora da lavorare.
Questa piccola classe è stata scritta per sfruttare l’ottimo pacchetto Console_ ProgressBar di PEAR (non reinventare la ruota!)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php
 
/**
 * progressbar task
 *
 * PEAR's Console_ProgressBar is required.
 * If Console_ProgressBar is not installed, no bar is displayed and no error is given
 * @see http://pear.php.net/package/Console_ProgressBar
 *
 * Usage: extend this class instead of sfBaseTask in your task.
 *        in your execute() method, call $this->init() and then other methods
 *        where appropriate.
 *
 * @author  Massimiliano Arione
 */
abstract class progressbarTask extends sfBaseTask
{
  protected
    $bar,
    $hasBar = false;
 
  /**
   * initialize ProgressBar
   */
  protected function init()
  {
    $this->hasBar = @include_once 'Console/ProgressBar.php';
  }
 
  /**
   * start bar
   * @param integer $count total number of items
   */
  protected function start($count = 0)
  {
    if ($this->hasBar)
    {
      $this->bar = new Console_ProgressBar('[%bar%] %percent% %elapsed%', '=>', ' ', 90, $count);
    }
  }
 
  /**
   * update the bar
   * @param integer $step
   */
  protected function update($step)
  {
    if ($this->hasBar)
    {
      $this->bar->update($step);
    }
  }
 
  /**
   * erase the bar
   */
  protected function erase()
  {
    if ($this->hasBar)
    {
      $this->bar->erase();
      $this->log('');
    }
  }
}

L’utilizzo è molto semplice: basta richiamare il metodo init(), quindi ogni volta che serve barra di progressione richiamare start(), update() ed erase() rispettivamente prima, durante e dopo il ciclo. Al metodo update() va passato un contatore, che deve essere incrementato nel ciclo stesso.

test complessi con sfTesterDoctrine

A volte può capitare di dover testare delle condizioni complesse su un oggetto Doctrine. In questi casi, il semplice array solitamente usato col metodo check() può non bastare. Per esempio mi è capitato recentemente di dover testare alcuni campi data con una condizione >= (maggiore o uguale).
Ma lo stesso metodo check() è abbastanza flessibile da accettare come secondo parametro non solo un array, ma anche un oggetto Doctrine_Query. Basterà quindi costruire le condizioni in questo modo e passarle, e il gioco è fatto.

personalizzare i filtri nel backend – 2

Se ricordate un vecchio post sull’applicazione della traduzione ai filtri del backend, sappiate che ora c’è una soluzione migliore:

1
2
3
4
if (sfConfig::get('sf_i18n'))
{
  $this->widgetSchema->getFormFormatter()->setTranslationCatalogue('sf_admin');
}

Tutto qui. Basta mettere queste poche righe di codice nelle classi BaseFormFilterDoctrine.class.php o BaseFormFilterPropel.class.php e il gioco è fatto. I filtri saranno tradotti, anche in altre eventuali lingue supportate dall’applicazione.