如何使用 PHPUnit 在 Symfony2 中设置数据库密集型单元测试?
我对测试领域很陌生,我想确保自己走在正确的轨道上.
I am quite new to the world of testing and I want to make sure I am on the right track.
我正在尝试使用 phpunit 在 symfony2 项目中设置单元测试.
I am trying to setup unit tests in a symfony2 project using phpunit.
PHPUnit 正在运行,并且简单的默认控制器测试运行良好.(然而,这不是关于功能测试,而是对我的应用程序进行单元测试.)
PHPUnit is working and the simple default controller tests work fine. (Yet this is not about functional testing but unit testing my application.)
不过,我的项目在很大程度上依赖于数据库交互,据我了解 phpunit 的文档,我应该基于 PHPUnit_Extensions_Database_TestCase
设置一个类,然后为我的数据库创建夹具并从那里开始工作.
My project relies heavily on database interactions though, and as far as I understand from phpunit's documentation, I should set up a class based on PHPUnit_Extensions_Database_TestCase
, then create fixtures for my db and work from there.
然而,symfony2 只提供了一个 WebTestCase
类,它只从 PHPUnit_Framework_TestCase
扩展开箱即用.
Yet, symfony2 only offers a WebTestCase
class which only extends from PHPUnit_Framework_TestCase
out of the box.
所以我假设我应该创建自己的 DataBaseTestCase
是否正确,它主要复制 WebTestCase
,唯一的区别是它从 PHPUnit_Extensions_Database_TestCase
扩展> 并实现其所有抽象方法?
So am I right to assume that I should create my own DataBaseTestCase
which mostly copies WebTestCase
, only difference being that it extends from PHPUnit_Extensions_Database_TestCase
and implements all its abstract methods?
或者关于以数据库为中心的测试,symfony2 是否还有另一个内置"推荐的工作流程?
Or is there another "built-in" recommended workflow for symfony2 concerning database-centric tests?
因为我想确保我的模型存储和检索正确的数据,所以我不想偶然测试 doctrine 的细节.
As I want to make sure that my models store and retrieve the right data, I do not want to end up testing the specifics of doctrine by accident.
推荐答案
tl;dr:
- 如果且仅当您想走完整个功能测试路线时,我建议您查找 Sgoettschkes 的答案.
- 如果您想对应用程序进行单元测试并且必须测试与数据库交互的代码,请继续阅读或直接跳转到symfony2 文档
(还有一个更新的版本也在谈论 使用 symfony5 的装置进行测试)
<小时>我最初的问题中有某些方面表明我缺乏对单元测试和功能测试之间差异的理解.(正如我所写的,我想对应用程序进行单元测试,但同时也在谈论控制器测试;那些是按定义进行的功能测试).
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.
相关文章