modelsManager not set in Phalcon Unittest

旧城冷巷雨未停 提交于 2019-12-12 04:18:35

问题


I'm integrating PHPUnit in my Phalcon project. I had it running correctly in MAMP, but when I run phpunit on my server, I keep getting some errors.

This is UnitTestCase:

<?php

use \Phalcon\Di;
use \Phalcon\DI\FactoryDefault;
use \Phalcon\Test\UnitTestCase as PhalconTestCase;

use \Phalcon\Mvc\View;
use \Phalcon\Crypt;
use \Phalcon\Mvc\Dispatcher;
use \Phalcon\Mvc\Dispatcher as PhDispatcher;
use \Phalcon\Mvc\Url as UrlResolver;
use \Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;
use \Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use \Phalcon\Mvc\Model\Metadata\Files as MetaDataAdapter;
use \Phalcon\Session\Adapter\Files as SessionAdapter;
use \Phalcon\Flash\Direct as Flash;
use \Phalcon\Logger;
use \Phalcon\Events\Manager as EventsManager;
use \Phalcon\Logger\Adapter\File as LoggerFile;
use \Phalcon\Mvc\Model\Manager as ModelsManager;


abstract class UnitTestCase extends PhalconTestCase
{
    /**
     * @var \Voice\Cache
     */
    protected $_cache;

    /**
     * @var \Phalcon\Config
     */
    protected $_config;

    /**
     * @var bool
     */
    private $_loaded = false;

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

        DI::reset();

        $config = include APP_DIR . '/config/config.php';

        /**
         * The URL component is used to generate all kind of urls in the application
         */
        $di->set('url', function () use ($config) {
            $url = new UrlResolver();
            $url->setBaseUri($config->application->baseUri);
            return $url;
        }, true);

        /**
         * Setting up the view component
         */
        $di->set('view', function () use ($config) {

            $view = new View();

            $view->setViewsDir($config->application->viewsDir);

            $view->registerEngines(array(
                '.volt' => function ($view, $di) use ($config) {

                    $volt = new VoltEngine($view, $di);

                    $volt->setOptions(array(
                        'compiledPath' => $config->application->cacheDir . 'volt/',
                        'compiledSeparator' => '_'
                    ));

                    return $volt;
                }
            ));

            return $view;
        }, true);

        ...and some more...

        $di->set(
            'modelsManager',
            function()
            {
                return new \Phalcon\Mvc\Model\Manager();
            }
        );

        parent::setUp($di, $config);

        $this->_loaded = true;
    }

    /**
     * Check if the test case is setup properly
     *
     * @throws \PHPUnit_Framework_IncompleteTestError;
     */
    public function __destruct()
    {
        if (!$this->_loaded) {
            throw new \PHPUnit_Framework_IncompleteTestError('Please run parent::setUp().');
        }
    }
}

So, when I run this on my local machine, this works fine. When I run it on the server, it throws:

Phalcon\Di\Exception: Service 'modelsManager' wasn't found in the dependency injection container

What am I doing wrong?


回答1:


Instead of setting up everything separately in your test, you should rather go for kind of an bootstrap solution.

My bootstrap file encloses in short TestHelper.php:

<?php
ini_set('display_errors',1);
error_reporting(E_ALL);

defined('APPLICATION_ENV') || define('APPLICATION_ENV', getenv('APPLICATION_ENV') ?: 'developer');
defined('APPLICATION_DIR') || define('APPLICATION_DIR', 'app');
defined('APPLICATION_PATH') || define('APPLICATION_PATH', realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . APPLICATION_DIR) . DIRECTORY_SEPARATOR);

use Phalcon\DI;

    $config  = include_once(APPLICATION_PATH . 'config' . DIRECTORY_SEPARATOR . 'config.php');
    $di      = new Phalcon\DI\FactoryDefault();
    $di->set('config', $config);

    $application = new \Phalcon\Mvc\Application($di);

    include_once(APPLICATION_PATH . 'autoload.php');

DI::setDefault($di);

$_SESSION = [];

Supported with proper configuration in phpunit.xml:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./TestHelper.php"
         backupGlobals="false"
         backupStaticAttributes="true"
         verbose="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="true">

    <testsuites>
        <testsuite name="Application - Testsuite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>

    <filter>
        <blacklist>
              <directory>../vendor</directory>
        </blacklist>
    </filter>

    <logging>
        <log type="coverage-html" target="../public/build/coverage" title="PHP Code Coverage"
             charset="UTF-8" yui="true" highlight="true"
             lowUpperBound="35" highLowerBound="70"/>
        <log type="coverage-clover" target="../public/build/logs/clover.xml"/>
        <log type="junit" target="../public/build/logs/junit.xml" logIncompleteSkipped="false"/>
    </logging>

</phpunit>

Bootstrap file should have everything what is necessary for your full application to run. Remember, that you are testing things, so it should not replace any logic, just define what should be defined at the very beggining of your standard index.php file and include what has to bu included, but keep away from running anything related to $application->handle(). You are just warming up your app, building all dependencies into it. My final index.php differ from my bootsrap with one try/catch block, custom error2exception handler and and echo $application->handle()->getContent();.

All is enclosed in structure like this:

* app/
|  |- config/
|  |- ...
|  '- autoload.php
* public/
|  |- css/
|  |- ...
|  '- index php
* vendor/
* tests/
   * app/
   |- // whole app/ structure
   |- TestHelper.php
   '- phpunit.xml 

Once your app is - I guess - working properly except tests, you should try to go proper way to inherit everything from it original struture, instead of declaring everything for each test.

Exampleous test /tests/app/models/services/DeviationTest.php for /app/models/services/deviation.php:

<?php

namespace Application\Services;

use \Application\Entities\Keywords;

/**
 * Generated by PHPUnit_SkeletonGenerator on 2015-09-18 at 10:24:22.
 */
class DeviationTest extends \PHPUnit_Framework_TestCase
{

    /**
     * @var Deviation
     */
    protected $object;
    protected $keyword;

    protected function setUp() {
        global $di;

        $this->object    = new Deviation($di);
        $this->keyword   = Keywords::findFirst('enabled = true AND text = "biura podróży"');
    }

    protected function tearDown() {

    }

    public function testGetDI() {
        $this->object->getDI();
    }

    public function testGet() {


        $this->object->get($this->keyword);
        $this->object->get($this->keyword, date('Y-m-d', strtotime('-1 day')));
        $this->object->get($this->keyword, date('Y-m-d'));

        return $this->object;
    }

    public function testGetOnDate() {

        $result = $this->object->get($this->keyword, date('Y-m-d', strtotime('-1 day')));
        print_r($result);

    }

    /**
     * @depends testGet
     */
    public function testCache($object) {

        $result = $object->get($this->keyword, date('Y-m-d', strtotime('-1 day')));
        $result = $object->get($this->keyword, date('Y-m-d', strtotime('-1 day')));
        $result = $object->get($this->keyword, date('Y-m-d', strtotime('-1 day')));

    }

}

As methods are made in way that if anything goes wrong they throw exceptions, I don't even have need to make any assertions - for now, it's an acceptance test.




回答2:


I just ran into the same issue and took me some time to figure it out. I obviously do include all the services from a separated 'bootstrap' file to prevent missing/duplicating DI services.

The issue was resolved for me by adding:

 /**
 * Function to setup the test case
 */
public function setUp()
{
    // Get reference to the global DI var (with all my registered services):
    global $di;
    // Setup parent:
    parent::setUp();
    // --------------------------------------------------
    // THIS IS WHAT SOLVED IT FOR ME, since Phalcon
    // Set default DI 
    // uses the \Phalcon\Di::getDefault() for handling queries from a model:
    \Phalcon\Di::setDefault($di);
    // --------------------------------------------------
    // Set the DI:
    $this->setDI($di);
}


来源:https://stackoverflow.com/questions/34981380/modelsmanager-not-set-in-phalcon-unittest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!