Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit53174e0

Browse files
committed
Merge pull requestsymfony#2407 from Sgoettschkes/issue480
[WIP] Adding a testing/database cookbook
2 parents7627f76 +00d24fa commit53174e0

File tree

3 files changed

+136
-0
lines changed

3 files changed

+136
-0
lines changed

‎cookbook/map.rst.inc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
* :doc:`/cookbook/testing/simulating_authentication`
144144
* :doc:`/cookbook/testing/insulating_clients`
145145
* :doc:`/cookbook/testing/profiling`
146+
* :doc:`/cookbook/testing/database`
146147
* :doc:`/cookbook/testing/doctrine`
147148
* :doc:`/cookbook/testing/bootstrap`
148149
* (email) :doc:`/cookbook/email/testing`

‎cookbook/testing/database.rst

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
..index::
2+
single: Tests; Database
3+
4+
How to test code which interacts with the database
5+
==================================================
6+
7+
If your code interacts with the database, e.g. reads data from or stores data into
8+
it, you need to adjust your tests to take this into account. There are many ways
9+
how to deal with this. In a unit test, you can create a mock for a ``Repository``
10+
and use it to return expected objects. In a functional test, you may need to
11+
prepare a test database with predefined values, so a test always has the same data
12+
to work with.
13+
14+
Mocking the ``Repository`` in a Unit Test
15+
-----------------------------------------
16+
17+
If you want to test code which depends on a doctrine ``Repository`` in isolation, you
18+
need to mock the ``Repository``. Normally you get the ``Repository`` from the ``EntityManager``,
19+
so you would need to mock those as well. Suppose the class you want to test looks like this::
20+
21+
namespace Acme\DemoBundle\Salary;
22+
23+
use Doctrine\Common\Persistence\ObjectManager;
24+
25+
class SalaryCalculator
26+
{
27+
private $entityManager;
28+
29+
public function __construct(ObjectManager $entityManager)
30+
{
31+
$this->entityManager = $entityManager;
32+
}
33+
34+
public function calculateTotalSalary($id)
35+
{
36+
$employeeRepository = $this->entityManager->getRepository('AcmeDemoBundle::Employee');
37+
$employee = $userRepository->find($id);
38+
39+
return $employee->getSalary() + $employee->getBonus();
40+
}
41+
}
42+
43+
As the ``ObjectManager`` gets injected into the class through the constructor, it's
44+
easy to pass a mock object within a test::
45+
46+
use Acme\DemoBundle\Salary\SalaryCalculator;
47+
48+
class SalaryCalculatorTest extends \PHPUnit_Framework_TestCase
49+
{
50+
51+
public function testCalculateTotalSalary()
52+
{
53+
// First, mock the object to be used in the test
54+
$employee = $this->getMock('\Acme\DemoBundle\Entity\Employee');
55+
$employee->expects($this->once())
56+
->method('getSalary')
57+
->will($this->returnValue(1000));
58+
$employee->expects($this->once())
59+
->method('getBonus')
60+
->will($this->returnValue(1100));
61+
62+
// Now, mock the repository so it returns the mock of the employee
63+
$employeeRepository = $this->getMockBuilder('\Doctrine\ORM\EntityRepository')
64+
->disableOriginalConstructor()
65+
->getMock();
66+
$employeeRepository->expects($this->once())
67+
->method('find')
68+
->will($this->returnValue($employee));
69+
70+
// Last, mock the EntityManager to return the mock of the repository
71+
$entityManager = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager')
72+
->disableOriginalConstructor()
73+
->getMock();
74+
$entityManager->expects($this->once())
75+
->method('getRepository')
76+
->will($this->returnValue($employeeRepository));
77+
78+
$salaryCalculator = new SalaryCalculator($entityManager);
79+
$this->assertEquals(1100, $salaryCalculator->calculateTotalSalary(1));
80+
}
81+
}
82+
83+
We are building our mocks from the inside out, first creating the employee which
84+
gets returned by the ``Repository`` which itself gets returned by the ``EntityManager``.
85+
This way, no real class is involved in testing.
86+
87+
Changing database settings for functional tests
88+
-----------------------------------------------
89+
90+
If you have functional tests, you want them to interact with a real database.
91+
Most of the time you want to use a dedicated database connection to make sure
92+
not to overwrite data you entered when developing the application and also
93+
to be able to clear the database before every test.
94+
95+
To do this, you can specify a database configuration which overwrites the default
96+
configuration:
97+
98+
..code-block::yaml
99+
100+
# app/config/config_test.yml
101+
doctrine:
102+
# ...
103+
dbal:
104+
host:localhost
105+
dbname:testdb
106+
user:testdb
107+
password:testdb
108+
109+
..code-block::xml
110+
111+
<!-- app/config/config_test.xml-->
112+
<doctrine:config>
113+
<doctrine:dbal
114+
host="localhost"
115+
dbname="testdb"
116+
user="testdb"
117+
password="testdb"
118+
>
119+
</doctrine:config>
120+
121+
..code-block::php
122+
123+
// app/config/config_test.php
124+
$configuration->loadFromExtension('doctrine', array(
125+
'dbal' => array(
126+
'host' => 'localhost',
127+
'dbname' => 'testdb',
128+
'user' => 'testdb',
129+
'password' => 'testdb',
130+
),
131+
));
132+
133+
Make sure that your database runs on localhost and has the defined database and
134+
user credentials set up.

‎cookbook/testing/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ Testing
88
simulating_authentication
99
insulating_clients
1010
profiling
11+
database
1112
doctrine
1213
bootstrap

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp