@@ -15,67 +15,57 @@ Symfony integrates with an independent library called `PHPUnit`_ to give you a
15
15
rich testing framework. This article won't cover PHPUnit itself, which has its
16
16
own excellent `documentation `_.
17
17
18
- Before creating your first test, install the `PHPUnit Bridge component `_, which
19
- wraps the original PHPUnit binary to provide additional features:
18
+ Before creating your first test, install the PHPUnit with the following command:
20
19
21
20
.. code-block :: terminal
22
21
23
- $ composer require --dev symfony /phpunit-bridge
22
+ $ composer require --dev phpunit /phpunit
24
23
25
- After the library downloads, try executing PHPUnit by running (the first time
26
- you run this, it will download PHPUnit itself and make its classes available in
27
- your app):
24
+ After the library is installed, try executing PHPUnit by running:
28
25
29
26
.. code-block :: terminal
30
27
31
- $ ./bin/phpunit
28
+ $ ./vendor/ bin/phpunit
32
29
33
30
.. note ::
34
31
35
- The ``./bin/phpunit `` command is created by :ref: `Symfony Flex <symfony-flex >`
36
- when installing the ``phpunit-bridge `` package. If the command is missing, you
37
- can remove the package (``composer remove symfony/phpunit-bridge ``) and install
38
- it again. Another solution is to remove the project's ``symfony.lock `` file and
39
- run ``composer install `` to force the execution of all Symfony Flex recipes.
32
+ :ref: `Symfony Flex <symfony-flex >` has automatically created ``phpunit.xml.dist ``
33
+ and ``tests/bootstrap.php ``. If the files are missing, you can remove the package
34
+ (``composer remove phpunit/phpunit ``) and install it again.
40
35
41
36
Each test is a PHP class that should live in the ``tests/ `` directory of
42
37
your application. If you follow this rule, then you can run all of your
43
38
application's tests with the same command as before.
44
39
45
- PHPUnit is configured by the ``phpunit.xml.dist `` file in the root of your
46
- Symfony application.
47
-
48
- .. tip ::
49
-
50
- Use the ``--coverage-* `` command options to generate code coverage reports.
51
- Read the PHPUnit manual to learn more about `code coverage analysis `_.
40
+ PHPUnit is configured by the ``phpunit.xml.dist `` file in the root of your application.
52
41
53
42
Types of Tests
54
43
--------------
55
44
45
+ To get a common language and shared context, it is important to define a what different
46
+ types of tests really mean. Symfony will use the following definition. If you have
47
+ learned something different, that is not necessarily wrong. It is just different
48
+ from what the Symfony documentation is using.
49
+
56
50
`Unit Tests `_
57
51
These tests ensure that *individual * units of source code (e.g. a single
58
52
class) behave as intended.
59
53
60
54
`Integration Tests `_
61
55
These tests test a combination of classes and commonly interact with
62
56
Symfony's service container. These tests do not yet cover the full
63
- working application, those are called *Functional tests *.
57
+ working application, those are called *Application tests *.
64
58
65
- `Functional Tests `_
66
- Functional tests test the behavior of a complete application. They
59
+ `Application Tests `_
60
+ Application tests test the behavior of a complete application. They
67
61
make HTTP requests and test that the response is as expected.
68
62
69
- `End to End Tests (E2E) `_
70
- At last, end to end tests test the application as a real user. They use
71
- a real browser and real integrations with external services.
72
-
73
63
Unit Tests
74
64
----------
75
65
76
66
A `unit test `_ ensures that individual units of source code (e.g. a single
77
67
class or some specific method in some class) meet their design and behave
78
- as intended. Writing Symfony unit tests is no different from writing
68
+ as intended. Writing unit tests is a Symfony application no different from writing
79
69
standard PHPUnit unit tests. You can learn about it in the PHPUnit
80
70
documentation: `Writing Tests for PHPUnit `_.
81
71
@@ -85,52 +75,49 @@ of your application for unit tests. So, if you're testing a class in the
85
75
Autoloading is automatically enabled via the ``vendor/autoload.php `` file
86
76
(as configured by default in the ``phpunit.xml.dist `` file).
87
77
88
- You can run tests using the ``bin/phpunit `` command:
78
+ You can run tests using the ``./vendor/ bin/phpunit `` command:
89
79
90
80
.. code-block :: terminal
91
81
92
82
# run all tests of the application
93
- $ php bin/phpunit
83
+ $ php ./vendor/ bin/phpunit
94
84
95
85
# run all tests in the Util/ directory
96
- $ php bin/phpunit tests/Util
86
+ $ php ./vendor/ bin/phpunit tests/Util
97
87
98
88
# run tests for the Calculator class
99
- $ php bin/phpunit tests/Util/CalculatorTest.php
89
+ $ php ./vendor/ bin/phpunit tests/Util/CalculatorTest.php
100
90
101
91
Integration Tests
102
92
-----------------
103
93
104
- TODO: KernelTestCase
105
-
106
- Accessing the Container
107
- ~~~~~~~~~~~~~~~~~~~~~~~
108
-
109
- You can get the same container used in the application, which only includes
110
- the public services::
111
-
112
- public function testSomething()
113
- {
114
- $kernel = self::bootKernel();
115
- $container = $kernel->getContainer();
116
- $someService = $container->get('the-service-ID');
117
-
118
- // ...
119
- }
94
+ An integration test will test a larger part of your application compared to a unit
95
+ test. Integration tests will use the Kernel to fetch a service from the dependency
96
+ injection container.
120
97
121
- Symfony tests also have access to a special container that includes both the
98
+ Symfony tests have access to a special container that includes both the
122
99
public services and the non-removed :ref: `private services <container-public >`
123
100
services::
124
101
125
- public function testSomething()
102
+ // tests/Service/AcmeServiceTest.php
103
+ namespace App\Tests\Service;
104
+
105
+ use App\Service\AcmeService;
106
+ use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
107
+
108
+ class AcmeServiceTest extends KernelTestCase
126
109
{
127
- // this call is needed; otherwise the container will be empty
128
- self::bootKernel();
110
+ public function testSomething()
111
+ {
112
+ // this call is needed; otherwise the container will be empty
113
+ self::bootKernel();
129
114
130
- $container = self::$container;
131
- // $someService = $container->get('the-service-ID' );
115
+ $container = self::$container;
116
+ $someService = $container->get(AcmeService::class );
132
117
133
- // ...
118
+ $result = $someService->something();
119
+ $this->assertTrue($result);
120
+ }
134
121
}
135
122
136
123
.. caution ::
@@ -140,55 +127,21 @@ services::
140
127
other services). The solution is to declare those private services as public
141
128
in the ``config/services_test.yaml `` file.
142
129
143
- .. TODO is this really different from self::$container and how to access
144
- this in KernelTestCase?
145
-
146
- Finally, for the most rare edge-cases, Symfony includes a special container
147
- which provides access to all services, public and private. This special
148
- container is a service that can be get via the normal container::
149
-
150
- public function testSomething()
151
- {
152
- $client = self::createClient();
153
- $normalContainer = $client->getContainer();
154
- $specialContainer = $normalContainer->get('test.service_container');
155
-
156
- // $somePrivateService = $specialContainer->get('the-service-ID');
157
-
158
- // ...
159
- }
160
-
161
- Mocking Services
162
- ~~~~~~~~~~~~~~~~
163
-
164
- TODO
165
-
166
- .. _functional-tests :
167
-
168
- Functional Tests
169
- ----------------
170
-
171
- Functional tests check the integration of the different layers of an
172
- application (from the routing to the views). They are no different from unit
173
- tests as far as PHPUnit is concerned, but they have a very specific workflow:
174
-
175
- * Make a request;
176
- * Click on a link or submit a form;
177
- * Test the response;
178
- * Rinse and repeat.
179
-
180
- Before creating your first test, install the ``symfony/test-pack `` which
181
- requires multiple packages providing some of the utilities used in the
182
- tests:
130
+ .. tip ::
183
131
184
- .. code-block :: terminal
132
+ To run your application tests, the ``KernelTestCase `` class needs to know which
133
+ is the application kernel to bootstrap it. The kernel class is usually
134
+ defined in the ``KERNEL_CLASS `` environment variable (included in the
135
+ default ``.env.test `` file provided by Symfony Flex):
185
136
186
- $ composer require --dev symfony/test-pack
137
+ If your use case is more complex, you can also override the
138
+ ``createKernel() `` or ``getKernelClass() `` methods of your functional test,
139
+ which take precedence over the ``KERNEL_CLASS `` env var.
187
140
188
141
Set-up your Test Environment
189
142
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190
143
191
- The Client used by functional tests creates a Kernel that runs in a special
144
+ The tests creates a Kernel that runs in a special
192
145
``test `` environment. Since Symfony loads the ``config/packages/test/*.yaml ``
193
146
in the ``test `` environment, you can tweak any of your application's settings
194
147
specifically for testing.
@@ -236,7 +189,7 @@ You can also use a different environment entirely, or override the default
236
189
debug mode (``true ``) by passing each as options to the ``createClient() ``
237
190
method::
238
191
239
- $client = static::createClient ([
192
+ self::bootKernel ([
240
193
'environment' => 'my_test_env',
241
194
'debug' => false,
242
195
]);
@@ -300,7 +253,7 @@ that ensures that each test is run with the same unmodified database:
300
253
301
254
$ composer require --dev dama/doctrine-test-bundle
302
255
303
- Now, enable it as a PHPUnit extension or listener :
256
+ Now, enable it as a PHPUnit extension:
304
257
305
258
.. code-block :: xml
306
259
@@ -373,10 +326,34 @@ Empty the database and reload *all* the fixture classes with:
373
326
374
327
For more information, read the `DoctrineFixturesBundle documentation `_.
375
328
376
- Write Your First Functional Test
377
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
329
+ .. _functional-tests :
330
+
331
+ Application Tests
332
+ -----------------
333
+
334
+ Application tests check the integration of all the different layers of the
335
+ application (from the routing to the views). They are no different from unit tests
336
+ or integration tests as far as PHPUnit is concerned, but they have a very specific
337
+ workflow:
338
+
339
+ * Make a request;
340
+ * Click on a link or submit a form;
341
+ * Test the response;
342
+ * Rinse and repeat.
378
343
379
- Functional tests are PHP files that typically live in the ``tests/Controller ``
344
+ Before creating your first test, install the ``symfony/test-pack `` which
345
+ requires multiple packages providing some of the utilities used in the
346
+ tests:
347
+
348
+ .. code-block :: terminal
349
+
350
+ $ composer require --dev symfony/test-pack
351
+
352
+
353
+ Write Your First Application Test
354
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
355
+
356
+ Application tests are PHP files that typically live in the ``tests/Controller ``
380
357
directory of your application. If you want to test the pages handled by your
381
358
``PostController `` class, start by creating a new ``PostControllerTest.php ``
382
359
file that extends a special ``WebTestCase `` class.
@@ -400,17 +377,6 @@ As an example, a test could look like this::
400
377
}
401
378
}
402
379
403
- .. tip ::
404
-
405
- To run your functional tests, the ``WebTestCase `` class needs to know which
406
- is the application kernel to bootstrap it. The kernel class is usually
407
- defined in the ``KERNEL_CLASS `` environment variable (included in the
408
- default ``.env.test `` file provided by Symfony):
409
-
410
- If your use case is more complex, you can also override the
411
- ``createKernel() `` or ``getKernelClass() `` methods of your functional test,
412
- which take precedence over the ``KERNEL_CLASS `` env var.
413
-
414
380
In the above example, you validated that the HTTP response was successful. The
415
381
next step is to validate that the page actually contains the expected content.
416
382
The ``createClient() `` method returns a client, which is like a browser that
@@ -495,7 +461,7 @@ returns a ``Crawler`` instance.
495
461
496
462
.. tip ::
497
463
498
- Hardcoding the request URLs is a best practice for functional tests. If the
464
+ Hardcoding the request URLs is a best practice for application tests. If the
499
465
test generates URLs using the Symfony router, it won't detect any change
500
466
made to the application URLs which may impact the end users.
501
467
@@ -718,7 +684,7 @@ You can also override HTTP headers on a per request basis::
718
684
Reporting Exceptions
719
685
....................
720
686
721
- Debugging exceptions in functional tests may be difficult because by default
687
+ Debugging exceptions in application tests may be difficult because by default
722
688
they are caught and you need to look at the logs to see which exception was
723
689
thrown. Disabling catching of exceptions in the test client allows the exception
724
690
to be reported by PHPUnit::
@@ -1044,7 +1010,6 @@ Learn more
1044
1010
1045
1011
.. _`PHPUnit` : https://phpunit.de/
1046
1012
.. _`documentation` : https://phpunit.readthedocs.io/
1047
- .. _`PHPUnit Bridge component` : https://symfony.com/components/PHPUnit%20Bridge
1048
1013
.. _`Writing Tests for PHPUnit` : https://phpunit.readthedocs.io/en/stable/writing-tests-for-phpunit.html
1049
1014
.. _`unit test` : https://en.wikipedia.org/wiki/Unit_testing
1050
1015
.. _`$_SERVER` : https://www.php.net/manual/en/reserved.variables.server.php
0 commit comments