Skip to content

Commit e15ca16

Browse files
committed
Merge branch '2.1' into 2.2
Conflicts: components/http_foundation/introduction.rst
2 parents 2d7b3db + b022d23 commit e15ca16

File tree

6 files changed

+169
-4
lines changed

6 files changed

+169
-4
lines changed

book/internals.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ variables:
4646

4747
.. note::
4848

49-
Read more about the :doc:`HttpFoundation Component </components/http_foudation/introduction>`.
49+
Read more about the :doc:`HttpFoundation Component </components/http_foundation/introduction>`.
5050

5151
``HttpKernel`` Component
5252
~~~~~~~~~~~~~~~~~~~~~~~~

components/http_foundation/introduction.rst

+15-2
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,20 @@ class, which can make this even easier::
495495
));
496496

497497
This encodes your array of data to JSON and sets the ``Content-Type`` header
498-
to ``application/json``. If you're using JSONP, you can set the callback
499-
function that the data should be passed to::
498+
to ``application/json``.
499+
500+
.. caution::
501+
502+
To avoid `JSON Hijacking`_, you should pass an associative array as the
503+
outer-most array to ``JsonResponse`` and not an indexed array so that
504+
the final result is an object (e.g. ``{"object": "not inside an array"}``)
505+
instead of an array (e.g. ``[{"object": "inside an array"}]``).
506+
507+
JSONP Callback
508+
~~~~~~~~~~~~~~
509+
510+
If you're using JSONP, you can set the callback function that the data should
511+
be passed to::
500512

501513
$response->setCallback('handleResponse');
502514

@@ -515,3 +527,4 @@ The session information is in its own document: :doc:`/components/http_foundatio
515527
.. _Packagist: https://packagist.org/packages/symfony/http-foundation
516528
.. _Nginx: http://wiki.nginx.org/XSendfile
517529
.. _Apache: https://tn123.org/mod_xsendfile/
530+
.. _`JSON Hijacking`: http://haacked.com/archive/2009/06/25/json-hijacking.aspx

cookbook/map.rst.inc

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
* :doc:`/cookbook/testing/simulating_authentication`
152152
* :doc:`/cookbook/testing/insulating_clients`
153153
* :doc:`/cookbook/testing/profiling`
154+
* :doc:`/cookbook/testing/database`
154155
* :doc:`/cookbook/testing/doctrine`
155156
* :doc:`/cookbook/testing/bootstrap`
156157
* (email) :doc:`/cookbook/email/testing`

cookbook/testing/database.rst

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

cookbook/testing/index.rst

+1
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

reference/configuration/monolog.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Monolog Configuration Reference
5454
subject: ~
5555
email_prototype:
5656
id: ~ # Required (when the email_prototype is used)
57-
factory-method: ~
57+
method: ~
5858
channels:
5959
type: ~
6060
elements: []

0 commit comments

Comments
 (0)