使用 LiipFunctionalTestBundle 和夹具进行独立功能测试? [英] Independent functional tests with LiipFunctionalTestBundle and fixtures?

查看:25
本文介绍了使用 LiipFunctionalTestBundle 和夹具进行独立功能测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

I'm adding tests to a Symfony2 project. Previously I used the same database for dev and test environments, it used a MySQL database already populated with the same data than on the production server.

The tests were working dependently because some tests depended on previous tests. For example if I had a shop website, I added a product in the cart then removed the product from the cart. So I needed to insert data by using a form, before being able to remove it.

Now I want to work with independent functional tests, because that's the recommended way (by one of Symfony2's developers).

I've configured LiipFunctionalTestBundle correctly to use a SQLite database in the test environment and I've started to add fixtures with DoctrineFixturesBundle.

But I don't know how much data I have to load for each functional test. What fixture should I load at the beginning of a test? How to deal with CRUD operations when the entity depends on other entities because of relationships between tables?

Let's say I'm developing a shop, I want a few tests:

  1. The user add some products in its cart
  2. The user remove one product from its cart
  3. The user order the remaining products

Should I create a different fixture for every step? It means that my fixtures will need to exist in many different states: empty cart, cart with one product ordered, etc. It seems correct to me but very time consuming, so I'm wondering if my idea is valid.

解决方案

For each test case is better to load less fixture as possible both for isolation and for performance (the test suite can go very slowly).

When fixture depends each other, you simply manage them with the doctrine reference and link each other, take care of the order also. As Example, suppose the simply user and role relations.

A generic class for manage role fixture:

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);
    }
}

A Dedicated class for the Simple Role

class LoadSimpleRoleData extends BaseLoadRoleData
{
    public function load(ObjectManager $manager)
    {
        $this->createRole($manager, Role::SIMPLE);
    }
}

A Dedicated class for the Admin Role

class LoadAdminRoleData extends BaseLoadRoleData
{
    public function load(ObjectManager $manager)
    {
        $this->createRole($manager, Role::ADMIN);
    }

}

And the user: A generic class for manage user fixture:

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;

    }
}

A Dedicated class for the Simple User

class LoadSimpleUserData extends BaseLoadUserData {

    /**
     * Load data fixtures with the passed EntityManager
     *
     * @param DoctrineCommonPersistenceObjectManager $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);

    }
}

A Dedicated class for the Admin User

class LoadAdminUserData extends BaseLoadUserData {

    /**
     * Load data fixtures with the passed EntityManager
     *
     * @param DoctrineCommonPersistenceObjectManager $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);

    }

Now you can use it separately, as example, based on the Liip Functional Test Bundle:

class LoginControllerTest {

    public function testAdminUserLogin()
    {
        $this->loadFixtures(array(
            'AcmeDemoBundleDataFixturesORMLoadAdminRoleData',
            'AcmeDemoBundleDataFixturesORMLoadAdminUserData'
        ));

        // 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
        // DoctrineCommonDataFixturesFixtureInterface
        $this->loadFixtures(array(
            'AcmeDemoBundleDataFixturesORMLoadSimpleRoleData',
            'AcmeDemoBundleDataFixturesORMLoadSimpleUserData'
        ));

        // you can now run your functional tests with a populated database
        $client = static::createClient();
        // ...

        // test the login with simple user credential

    }

}

Hope this help.

这篇关于使用 LiipFunctionalTestBundle 和夹具进行独立功能测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆