首页 > 解决方案 > Symfony 3.4 无法在测试中加载夹具:错误:在 null 上调用成员函数 get()

问题描述

我有以下用于测试控制器的 phpunit 测试:

DefaultControllerTest:_

namespace Tests\AppBundle\Controller;

use Tests\AppBundle\Controller\BasicHttpController;
use AppBundle\DataFixtures\Test\DummyUserFixtures;

/**
* @testtype Functional
*/
class DefaultControllerTest extends BasicHttpController
{
    /**
    * {@inheritdoc}
    */
    public function setUp()
    {
        $fixture = new DummyUserFixtures();
        $fixture->load($this->entityManager);
    }

    /**
    * Testing the Behavior when visiting the index page
    */
    public function testIndex()
    {
        $client = $this->client;
        $router=$client->getContainer()->get('router');
        $crawler = $client->request('GET', '/');
        $response=$client->getResponse();
        $this->assertTrue($client->getResponse()->isRedirect());
        $this->assertEquals($router->getRouteCollection()->get('fos_user_security_login')->getPath(),$response->headers->get('Location'));

        //@todo Create Dummy Users
        // $this->checkPanelAfterSucessfullLogin($crawler);
    }
}

这扩展了以下测试BasicHttpController(尝试应用 DRY 原则):

namespace Tests\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Doctrine\Common\DataFixtures\Purger\ORMPurger;

class BasicHttpController extends WebTestCase
{
    protected $entityManager=null;

    protected $client=null;

    /**
    * {@inheritdoc}
    */
    public function __construct()
    {
        parent::__construct();
        $this->client = static::createClient();
        $container = $this->client->getContainer();
        $doctrine = $container->get('doctrine');
        $this->entityManager=$doctrine->getManager();
    }

    /**
    * Remove all entities from the database
    */
    protected function truncateEntities()
    {
        $purger = new ORMPurger($this->entityManager());
        $purger->purge();
    }


    /**
    * {@inheritdoc}
    */
    public function tearDown()
    {
        $this->truncateEntities();
    }

    /**
    * @param username String the user's username
    * @param passwoρd String the user's password
    */
    protected function checkPanelAfterSucessfullLogin($crawler,string $username,string $password)
    {
        //Submitting the form
        $form=$crawler->selectButton('_submit')->form();
        $form['_username']=$username;
        $form['_password']=$password;

        $crawler=$crawler->submit($form);
        $response=$client->getResponse();
        $this->assertTrue($client->getResponse()->isRedirect());
        $client->followRedirect();

        //Checking header
        $headerDom=$crawler->filter('header')->childen()->filter('nav.navbar')->children();
        $this->assertCount(1,$headerDom->find('a.navbar-brand')); //homepage link
        $this->assertCount(1,$headerDom->find('a.btn-danger')); //Logout button
    }
}

如您所见,我尝试加载以下夹具:

namespace AppBundle\DataFixtures\Test;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Doctrine\Common\Persistence\ObjectManager;

class DummyUserFixtures extends AbstractFixture implements OrderedFixtureInterface,ContainerAwareInterface
{

    /**
    * @var ContainerInterface
    */
    private $container=null;


    /**
    * {@inheritDoc}
    */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    /**
    * Generic function that creates a user with provided information.
    * @param $name {String} The user's name
    * @param $surname {String} The user's surname
    * @param $username {String} The user's username
    * @param $password {String} The user's password
    * @param $email {String} The user's recovery email
    * @param $role {String} The user's system role
    * @param $phone {String | null} The user's phone number
    * @param $organization {String|null} The user's organization
    * @param $occupation {String|null} The user's occupation
    *
    * @return AppBundle\Entity\User
    */
    private function createUser($name,$surname,$username,$password,$email,$role,$phone=null,$organization=null,$occupation=null)
    {
        $fosUserManager=$this->container->get('fos_user.user_manager');

        /**
        * @var AppBundle\Entity\User
        */
        $user=$fosUserManager->createUser();
        $user->setUsername($username);
        $user->setEmail($email);
        $user->setPlainPassword($password);
        $user->setEnabled(true);
        $user->setRoles(array($role));

        $user->setName($name);
        $user->setSurname($surname);

        if($phone){
            $user->setPhone($phone);
        }

        if($organization){
            $user->setOrganization($organization);
        }

        if($occupation){
            $user->setOccupation($occupation);
        }

        $fosUserManager->updateUser($user, true);

        return $user;
    }

    /**
    * {@inheritDoc}
    */
    public function load(ObjectManager $manager)
    {
        $this->createUser('John','Doe','jdoe','simplepasswd','jdoe@example.com','ROLE_USER','+3021456742324','Acme Products','Soft Engineer');
        $this->createUser('Jackie','Chan','jchan','thesimplepasswd','jackiechan@example.com','ROLE_ADMIN','+302141232324','Holywood','Actor');
        $this->createUser('Chuck','Norris','chuck_norris','unhackablepasswd','chucknorris@example.com','ROLE_SUPERADMIN',null,'Universe','Master');
    }

    public function getOrder()
    {
       return 1;
    }
}

但由于某种原因,我收到以下错误:

有 1 个错误:

1) Tests\AppBundle\Controller\DefaultControllerTest::testIndex 错误:调用成员函数 get() on null

/home/vagrant/code/src/AppBundle/DataFixtures/Test/DummyUserFixtures.php:50 /home/vagrant/code/src/AppBundle/DataFixtures/Test/DummyUserFixtures.php:87 /home/vagrant/code/tests/AppBundle /Controller/DefaultControllerTest.php:19

进一步调试证明该错误是由以下行触发的DummyUserFixtures

    $fosUserManager=$this->container->get('fos_user.user_manager');

那么你知道如何通过夹具加载数据吗?

标签: phpsymfonydoctrinephpunitsymfony-3.4

解决方案


为了让它工作,你应该设置你从static::createClient()方法生成的服务容器,并通过$fixture->setContainer($container)

因此,一个好的方法是将容器定义为受保护的实例变量,BasicHttpController以便任何测试类(例如,DefaultControllerTest在您的情况下)都能够相应地加载固定装置。

所以使用的setUp方法和实例变量BasicHttpController应该如下:

//Namespace declaration goes there

class BasicHttpController extends WebTestCase
{
    protected $entityManager=null;

    protected $client=null;

    protected $container=null;

    /**
    * {@inheritdoc}
    */
    public function setUp()
    {
        $this->client = static::createClient();
        $this->container = $this->client->getContainer();
        $doctrine = $this->container->get('doctrine');
        $this->entityManager=$doctrine->getManager();
    }

    // Rest methods here
}

注意:在从您那里继承的类上,BasicHttpController可以定义setUp如下:

public function setUp()
{
   parent::setUp();
   // Add extra stuff here
}

所以你可以在测试之前做更多的设置引导。


推荐阅读