Symfony 使用LiipFunctionalTestBundle和夹具进行独立功能测试?

Symfony 使用LiipFunctionalTestBundle和夹具进行独立功能测试?,symfony,doctrine-orm,phpunit,functional-testing,liipfunctionaltestbundle,Symfony,Doctrine Orm,Phpunit,Functional Testing,Liipfunctionaltestbundle,我正在向Symfony2项目添加测试。以前,我在dev和test环境中使用了相同的数据库,它使用的MySQL数据库已经填充了与生产服务器上相同的数据 由于某些测试依赖于以前的测试,因此这些测试是独立工作的。例如,如果我有一个商店网站,我在购物车中添加了一个产品,然后从购物车中删除了该产品。所以我需要使用表单插入数据,然后才能删除它 现在我想使用独立的功能测试,因为这是最重要的 我已经正确地配置了在test环境中使用SQLite数据库,并且已经开始使用添加装置 但我不知道每次功能测试需要加载多少数

我正在向Symfony2项目添加测试。以前,我在
dev
test
环境中使用了相同的数据库,它使用的MySQL数据库已经填充了与生产服务器上相同的数据

由于某些测试依赖于以前的测试,因此这些测试是独立工作的。例如,如果我有一个商店网站,我在购物车中添加了一个产品,然后从购物车中删除了该产品。所以我需要使用表单插入数据,然后才能删除它

现在我想使用独立的功能测试,因为这是最重要的

我已经正确地配置了在
test
环境中使用SQLite数据库,并且已经开始使用添加装置

但我不知道每次功能测试需要加载多少数据。测试开始时我应该加载什么夹具?当实体由于表之间的关系而依赖于其他实体时,如何处理CRUD操作

假设我正在开发一个商店,我需要一些测试:

  • 用户在购物车中添加了一些产品
  • 用户从购物车中删除一个产品
  • 用户订购剩余的产品

  • 我应该为每个步骤创建不同的夹具吗?这意味着我的装置需要在许多不同的状态下存在:空车、订购了一个产品的车等等。这对我来说似乎是正确的,但非常耗时,所以我想知道我的想法是否有效。

    对于每个测试用例,为了隔离和性能,最好尽可能少地加载装置(测试套件可能进行得非常缓慢)

    当夹具相互依赖时,您只需使用条令引用来管理它们,并将它们相互链接,同时还要注意顺序。 例如,假设简单的用户和角色关系

    管理角色装置的通用类:

    abstract class BaseLoadRoleData extends AbstractFixture implements OrderedFixtureInterface
    {
    
    
        public function getOrder()
        {
            return 1;
        }
    
        protected function createRole(ObjectManager $manager, $rolename)
        {
            $role= new Role();
            $role->setName($rolename);
    
            $manager->persist($role);
            $manager->flush();
            $this->setReference('role-' . $rolename, $role);
        }
    }
    
    用于简单角色的专用类

    class LoadSimpleRoleData extends BaseLoadRoleData
    {
        public function load(ObjectManager $manager)
        {
            $this->createRole($manager, Role::SIMPLE);
        }
    }
    
    管理员角色的专用类

    class LoadAdminRoleData extends BaseLoadRoleData
    {
        public function load(ObjectManager $manager)
        {
            $this->createRole($manager, Role::ADMIN);
        }
    
    }
    
    以及用户: 用于管理用户设备的通用类:

    abstract class BaseLoadUserData extends AbstractFixture implements OrderedFixtureInterface
    {
    
        /**
         * @var ContainerInterface
         */
        private $container;
    
        /**
         * {@inheritDoc}
         */
        public function setContainer(ContainerInterface $container = null)
        {
            $this->container = $container;
        }
    
        public function getOrder()
        {
            return 2;
        }
    
        protected function buildUser($username, $firstName = "",$lastName ="")
        {
            $user= new User();
            $user->setUsername($username);
            $user->setFirstName($firstName);
            $user->setLastName($lastName);
    
            return $user;
    
        }
    }
    
    为简单用户提供的专用类

    class LoadSimpleUserData extends BaseLoadUserData {
    
        /**
         * Load data fixtures with the passed EntityManager
         *
         * @param Doctrine\Common\Persistence\ObjectManager $manager
         */
        function load(ObjectManager $manager)
        {
            $user = $this->buildUser($manager, "simple@example.com");
            $user->addRole($this->getReference('role-'.Role::SIMPLE));
            $manager->persist($user);
            $manager->flush();
            $this->setReference('user-' . "admin@example.com", $user);
    
        }
    }
    
    管理员用户的专用类

    class LoadAdminUserData extends BaseLoadUserData {
    
        /**
         * Load data fixtures with the passed EntityManager
         *
         * @param Doctrine\Common\Persistence\ObjectManager $manager
         */
        function load(ObjectManager $manager)
        {
            $user = $this->buildUser($manager, "admin@example.com");
            $user->addRole($this->getReference('role-'.Role::ADMIN));
            $manager->persist($user);
            $manager->flush();
            $this->setReference('user-' . "admin@example.com", $user);
    
        }
    
    现在,您可以单独使用它,例如,基于Liip功能测试包:

    class LoginControllerTest {
    
        public function testAdminUserLogin()
        {
            $this->loadFixtures(array(
                'Acme\DemoBundle\DataFixtures\ORM\LoadAdminRoleData',
                'Acme\DemoBundle\DataFixtures\ORM\LoadAdminUserData'
            ));
    
            // you can now run your functional tests with a populated database
            $client = static::createClient();
            // ...
    
            // test the login with admin credential
        }
    
        public function testSimpleUserLogin()
        {
            // add all your fixtures classes that implement
            // Doctrine\Common\DataFixtures\FixtureInterface
            $this->loadFixtures(array(
                'Acme\DemoBundle\DataFixtures\ORM\LoadSimpleRoleData',
                'Acme\DemoBundle\DataFixtures\ORM\LoadSimpleUserData'
            ));
    
            // you can now run your functional tests with a populated database
            $client = static::createClient();
            // ...
    
            // test the login with simple user credential
    
        }
    
    }
    

    希望有帮助。

    如果我也想用
    john
    bob
    名字测试用户,该怎么办?为john编写一个专用fixture类,并将其加载到专用测试类中我是否应该复制并粘贴
    LoadSimpleUserData
    类中的所有代码?没有更好的方法了吗?当然,您可以为create user等创建一个带有公共方法的层次结构,但它们只是test pourpose的fixture类,显然是必须管理项目演进的alway类(新的必填字段等)。我只发布示例代码,但在我的项目中,我使用最小层次结构创建通用测试用户,并直接调用方法,如
    createTestUSer($name,$姓氏)
    @a.L我已经更新了我的答案,我不知道现在我是否更清楚我的意思