@@ -15,67 +15,57 @@ Symfony integrates with an independent library called `PHPUnit`_ to give you a
1515rich testing framework. This article won't cover PHPUnit itself, which has its
1616own excellent `documentation `_.
1717
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:
2019
2120.. code-block :: terminal
2221
23- $ composer require --dev symfony /phpunit-bridge
22+ $ composer require --dev phpunit /phpunit
2423
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:
2825
2926.. code-block :: terminal
3027
31- $ ./bin/phpunit
28+ $ ./vendor/ bin/phpunit
3229
3330 .. note ::
3431
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.
4035
4136Each test is a PHP class that should live in the ``tests/ `` directory of
4237your application. If you follow this rule, then you can run all of your
4338application's tests with the same command as before.
4439
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.
5241
5342Types of Tests
5443--------------
5544
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+
5650`Unit Tests `_
5751 These tests ensure that *individual * units of source code (e.g. a single
5852 class) behave as intended.
5953
6054`Integration Tests `_
6155 These tests test a combination of classes and commonly interact with
6256 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 *.
6458
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
6761 make HTTP requests and test that the response is as expected.
6862
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-
7363Unit Tests
7464----------
7565
7666A `unit test `_ ensures that individual units of source code (e.g. a single
7767class 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
7969standard PHPUnit unit tests. You can learn about it in the PHPUnit
8070documentation: `Writing Tests for PHPUnit `_.
8171
@@ -85,52 +75,49 @@ of your application for unit tests. So, if you're testing a class in the
8575Autoloading is automatically enabled via the ``vendor/autoload.php `` file
8676(as configured by default in the ``phpunit.xml.dist `` file).
8777
88- You can run tests using the ``bin/phpunit `` command:
78+ You can run tests using the ``./vendor/ bin/phpunit `` command:
8979
9080.. code-block :: terminal
9181
9282 # run all tests of the application
93- $ php bin/phpunit
83+ $ php ./vendor/ bin/phpunit
9484
9585 # run all tests in the Util/ directory
96- $ php bin/phpunit tests/Util
86+ $ php ./vendor/ bin/phpunit tests/Util
9787
9888 # run tests for the Calculator class
99- $ php bin/phpunit tests/Util/CalculatorTest.php
89+ $ php ./vendor/ bin/phpunit tests/Util/CalculatorTest.php
10090
10191 Integration Tests
10292-----------------
10393
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.
12097
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
12299public services and the non-removed :ref: `private services <container-public >`
123100services::
124101
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
126109 {
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();
129114
130- $container = self::$container;
131- // $someService = $container->get('the-service-ID' );
115+ $container = self::$container;
116+ $someService = $container->get(AcmeService::class );
132117
133- // ...
118+ $result = $someService->something();
119+ $this->assertTrue($result);
120+ }
134121 }
135122
136123.. caution ::
@@ -140,55 +127,21 @@ services::
140127 other services). The solution is to declare those private services as public
141128 in the ``config/services_test.yaml `` file.
142129
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 ::
183131
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):
185136
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.
187140
188141Set-up your Test Environment
189142~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190143
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
192145``test `` environment. Since Symfony loads the ``config/packages/test/*.yaml ``
193146in the ``test `` environment, you can tweak any of your application's settings
194147specifically for testing.
@@ -236,7 +189,7 @@ You can also use a different environment entirely, or override the default
236189debug mode (``true ``) by passing each as options to the ``createClient() ``
237190method::
238191
239- $client = static::createClient ([
192+ self::bootKernel ([
240193 'environment' => 'my_test_env',
241194 'debug' => false,
242195 ]);
@@ -300,7 +253,7 @@ that ensures that each test is run with the same unmodified database:
300253
301254 $ composer require --dev dama/doctrine-test-bundle
302255
303- Now, enable it as a PHPUnit extension or listener :
256+ Now, enable it as a PHPUnit extension:
304257
305258.. code-block :: xml
306259
@@ -373,10 +326,34 @@ Empty the database and reload *all* the fixture classes with:
373326
374327 For more information, read the `DoctrineFixturesBundle documentation `_.
375328
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.
378343
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 ``
380357directory of your application. If you want to test the pages handled by your
381358``PostController `` class, start by creating a new ``PostControllerTest.php ``
382359file that extends a special ``WebTestCase `` class.
@@ -400,17 +377,6 @@ As an example, a test could look like this::
400377 }
401378 }
402379
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-
414380In the above example, you validated that the HTTP response was successful. The
415381next step is to validate that the page actually contains the expected content.
416382The ``createClient() `` method returns a client, which is like a browser that
@@ -495,7 +461,7 @@ returns a ``Crawler`` instance.
495461
496462.. tip ::
497463
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
499465 test generates URLs using the Symfony router, it won't detect any change
500466 made to the application URLs which may impact the end users.
501467
@@ -718,7 +684,7 @@ You can also override HTTP headers on a per request basis::
718684Reporting Exceptions
719685....................
720686
721- Debugging exceptions in functional tests may be difficult because by default
687+ Debugging exceptions in application tests may be difficult because by default
722688they are caught and you need to look at the logs to see which exception was
723689thrown. Disabling catching of exceptions in the test client allows the exception
724690to be reported by PHPUnit::
@@ -1044,7 +1010,6 @@ Learn more
10441010
10451011.. _`PHPUnit` : https://phpunit.de/
10461012.. _`documentation` : https://phpunit.readthedocs.io/
1047- .. _`PHPUnit Bridge component` : https://symfony.com/components/PHPUnit%20Bridge
10481013.. _`Writing Tests for PHPUnit` : https://phpunit.readthedocs.io/en/stable/writing-tests-for-phpunit.html
10491014.. _`unit test` : https://en.wikipedia.org/wiki/Unit_testing
10501015.. _`$_SERVER` : https://www.php.net/manual/en/reserved.variables.server.php
0 commit comments