We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Model, Db connection service and PHPunit

Hi all,

I'm starting to implement unit test in my Phalcon MVC app, and I'm struggling to make my models work there. I've picked up the phpunit example from the incubator, working well, I use the [ CoreTestCase->setUp() ] method to load/overwrite some services on the fly (locale, db, cache...), and my test are running fine.

Now comes the time to test the first function using models, and it fails. I get the following message: "Service 'db' wasn't found in the dependency injection container".

Some more details:

  • Service 'db' is managing the db connection (\Phalcon\Db\Adapter\Pdo\Mysql)
  • That happens when I try to save data using my email model [$mEmail->create();]
  • I make my models inherit from a modelStub class containing the static metaData mapping (no db connection required to instanciate the models)
  • if I dump the model DI [var_dump($mEmail->getDi()->getDb());] it shows the db service properly configured

I had a look at the modelManager class, but didn't have much success. Can anyone help me ? If not the model, what class is looking for the 'db' service ? Alternatively, is there a way to enforce all the classes reloading the DI once I've added some services in the setUp helper?

Thanks



24.8k

Nobody ever had this problem ?

This probably isn't the answer you're looking for, but when I'm doing tests, I just use a test database. Then in my test bootstrap file, I just point the DB service to a different databas.



24.8k

Hey Dylan,

Thank you for your answer, but my issue is a bit more complex that just loading a different databse. I use a MVC app and some shared services (not Phalcon once, some php classes uses accross modules/controllers) so I need to load my boostrap file (or most of it) to run tests.

But here is the problem: when using my models it seems like a "high level" phalcon class is not using the DI I've loaded. The models are properly loaded with all the correct attributes and correct DI, but when I try to execute a query it failed to find the 'db' service. I pressume there's an issue somewhere with $di = DI::getDefault();

To make it work, I have refactored all my file inclusions and reload the full app using the setUp method for each test. That seem to work, but that makes the tests seriously slower. See the code below:

A test I've written to test basic phalcon services:

class DiTest extends \CoreTestCase
{
    public function testCoreService()
    {
        $this->setUp(null, null, true);

        $oService = $this->di->get('db');
        $this->assertNotEmpty($oService, 'Db service empty / not loaded');

        $oService = $this->di->get('cache');
        $this->assertNotEmpty($oService, 'Cache/redis service empty / not loaded');

        /* .. */        
    }
}

the updated setUp() method, reloading the full MVC app when requested by the test:


 public function setUp(Phalcon\DiInterface $di = NULL, Phalcon\Config $config = NULL, $pbLoadMvc = false)
    {
        // Load any additional services that might be required during testing
        $di = DI::getDefault(); 

        // Get any DI components here. If you have a config, be sure to pass it to the parent
        if($pbLoadMvc)
        {
            $di = loadMvcDi($di);
        }

        parent::setUp($di);
        $this->_loaded = true;
    }

And finally the function that relaods the MVC:

function loadMvcDi($di)
{
    // Add any needed services to the DI here
    include(PATH_ROOT . '/apps/config/bootstrap.php');

    $oTestUser = $di->get('user');
    $oTestUser->loadSystemTestUser();
    $di->set('user', $oTestUser);

    if($di->has('session'))
    {
        //overwrite session settings from redis to file
    }

    if($di->has('db'))
    {
        //overwrite db settings
        $di->setShared('db', function() use ($___asConfig)
        {
            $oDb =  new \Phalcon\Db\Adapter\Pdo\Mysql($___asConfig['database']['phpunit'];
            if(!$oDb)
                exit('no db for phpunit tests');

            return $oDb;
        });
        $di->get('db');
    }

    return $di;
}

So if someone has a better/more efficient was to implemnent phpunit with a MVC, I'm a taker.