独立功能测试与LiipFunctionalTestBundle和固定装置? [英] Independent functional tests with LiipFunctionalTestBundle and fixtures?

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

问题描述

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



测试工作依赖,因为一些测试依赖于以前的测试。例如,如果我有一个商店网站,我在购物车中添加了一个产品,然后从购物车中取出产品。所以我需要使用表单插入数据,然后才能将其删除。



现在我想使用独立的功能测试,因为这是推荐的方式(由Symfony2的开发人员之一)



我已配置<一个href =https://github.com/liip/LiipFunctionalTestBundle =nofollow noreferrer> LiipFunctionalTestBundle 正确地在测试中使用SQLite数据库环境中,我已经开始使用 DoctrineFixturesBundle 添加灯具。



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



假设我正在开发一个商店,我想要几个测试: / p>


  1. 用户在购物车中添加一些产品

  2. 用户从其购物车中删除一个商品

  3. 用户订购剩余的产品

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

解决方案

对于每个测试用例,更好的是为隔离和性能加载更少的灯具(测试套件可以走得很慢) / p>

当夹具相互依赖时,您只需使用原则参考来管理它们,并相互链​​接,也可以处理订单。
作为示例,假设简单的用户和角色关系。



管理角色夹具的通用类:

 抽象类BaseLoadRoleData extends AbstractFixture实现OrderedFixtureInterface 
{


public function getOrder()
{
返回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);
}

}

而用户:
用于管理用户夹具的通用类:

 抽象类BaseLoadUserData extends AbstractFixture实现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 {

/ **
*加载数据夹具通过EntityManager
*
* @param Doctrine\Common\Persistence\ObjectManager $ manager
* /
函数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 {

/ **
*加载数据夹具,通过EntityManager
*
* @param Doctrine\Common\Persistence\ObjectManager $ manager
* /
函数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'
));

//您现在可以使用填充数据库运行功能测试
$ client = static :: createClient();
// ...

//用admin凭证测试登录
}

public function testSimpleUserLogin()
{
//添加所有实现
的fixtures类// Doctrine\Common\DataFixtures\FixtureInterface
$ this-> loadFixtures(array(
'Acme\DemoBundle\\ \\ DataFixtures\ORM\LoadSimpleRoleData',
'Acme\DemoBundle\DataFixtures\ORM\LoadSimpleUserData'
));

//您现在可以使用填充数据库运行功能测试
$ client = static :: createClient();
// ...

//用简单的用户凭证测试登录

}

}

希望这个帮助。


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

    }
}

A Dedicated class for the Admin 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);

    }

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

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

    }

}

Hope this help.

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

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