且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何使用 PHPUnit 在 Symfony2 中设置数据库密集型单元测试?

更新时间:2023-11-19 17:26:58

tl;dr:

我最初的问题中有某些方面表明我缺乏对单元测试和功能测试之间差异的理解.(正如我所写的,我想对应用程序进行单元测试,但同时也在谈论控制器测试;那些是按定义进行的功能测试).


There were certain aspects in my original question that make it clear that my understanding of the differences between unit testing and functional tests was lacking. (As I have written I want to unit test the application, yet was also talking about Controller test at the same time; and those are functional test by defintion).

单元测试只对服务有意义,对存储库没有意义.这些服务可以使用实体管理器的模拟.(我什至会说:如果可能的话,编写只期望实体被传递给它们的服务.然后你只需要创建这些实体的模拟,你的业务逻辑的单元测试就会变得非常简单.)

Unit testing only makes sense for services and not for repositories. And those services can use mocks of the entity manager. (I would even go as far as to say: If possible, write services that only expect entities to be passed into them. Then you only need to create mocks of those entities and your unit-tests of your business logic become very straightforward.)

我的应用程序的实际用例在 how 上的 symfony2 文档中得到了很好的反映测试与数据库交互的代码.

My actual use case for my application was pretty well reflected on the symfony2 docs on how to test code that interacts with the database.

他们为服务测试提供了这个示例:

They provide this example for a service test:

服务类:

use DoctrineCommonPersistenceObjectManager;

class SalaryCalculator
{
    private $entityManager;

    public function __construct(ObjectManager $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    public function calculateTotalSalary($id)
    {
        $employeeRepository = $this->entityManager
            ->getRepository('AppBundle:Employee');
        $employee = $employeeRepository->find($id);

        return $employee->getSalary() + $employee->getBonus();
    }
}

服务测试类:

namespace TestsAppBundleSalary;

use AppBundleSalarySalaryCalculator;
use AppBundleEntityEmployee;
use DoctrineORMEntityRepository;
use DoctrineCommonPersistenceObjectManager;

class SalaryCalculatorTest extends PHPUnit_Framework_TestCase
{
    public function testCalculateTotalSalary()
    {
        // First, mock the object to be used in the test
        $employee = $this->getMock(Employee::class);
        $employee->expects($this->once())
            ->method('getSalary')
            ->will($this->returnValue(1000));
        $employee->expects($this->once())
            ->method('getBonus')
            ->will($this->returnValue(1100));

        // Now, mock the repository so it returns the mock of the employee
        $employeeRepository = $this
            ->getMockBuilder(EntityRepository::class)
            ->disableOriginalConstructor()
            ->getMock();
        $employeeRepository->expects($this->once())
            ->method('find')
            ->will($this->returnValue($employee));

        // Last, mock the EntityManager to return the mock of the repository
        $entityManager = $this
            ->getMockBuilder(ObjectManager::class)
            ->disableOriginalConstructor()
            ->getMock();
        $entityManager->expects($this->once())
            ->method('getRepository')
            ->will($this->returnValue($employeeRepository));

        $salaryCalculator = new SalaryCalculator($entityManager);
        $this->assertEquals(2100, $salaryCalculator->calculateTotalSalary(1));
    }
}

这种测试不需要测试数据库,只需要模拟.

No test database required for those kind of test, only mocking.

因为测试业务逻辑很重要,而不是持久层.

As it is important to test the business logic, not the persistence layer.

只有对于功能测试来说,拥有自己的测试数据库才有意义,然后应该建立和拆除,最大的问题应该是:

Only for functional tests does it make sense to have its own test database that one should build and tear down afterwards, and the big question should be:

功能测试什么时候有意义?

When do functional test make sense?

我曾经认为测试所有的东西是正确的答案;然而,在使用了许多本身几乎没有经过测试驱动开发的遗留软件之后,我变得更加懒惰务实,并认为某些功能可以正常工作,直到被错误证明否则.

I used to think that test all the things is the right answer; yet after working with lots of legacy software that in itself was barely test-driven developed I have become a bit more lazypragmatic and consider certain functionality as working until proven otherwise by a bug.

假设我有一个应用程序可以解析 XML,从中创建一个对象,并将这些对象存储到数据库中.如果已知将对象存储到数据库的逻辑是有效的(例如:公司需要数据并且到目前为止还没有坏),即使该逻辑是一大堆丑陋的废话,也没有迫在眉睫 需要对此进行测试.因为我需要确保我的 XML 解析器提取正确的数据.我可以从经验中推断出正确的数据将被存储.

Assume I have an application that parses an XML, creates an object out of it, and stores those objects into a database. If the logic that stores the objects to the database is known to work (as in: the company requires the data and is, as of yet, not broke), and even if that logic is a big ugly pile of crap, there is no imminent need to test that. As all I need to make sure that my XML parser extracts the right data. I can infer from experience that the right data will be stored.

在某些情况下,功能测试非常重要,例如,如果您要编写在线商店.将购买的物品存储到数据库中对业务至关重要,在这里对整个测试数据库进行功能测试是绝对有意义的.

There are scenarios where functional test are quite important, i.e. if one were to write an online shop. There it would be business critical that bought items get stored into the database and here functional tests with the whole test database make absolute sense.