<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Cem Ünalan</title>
    <description>The latest articles on DEV Community by Cem Ünalan (@raicem).</description>
    <link>https://dev.to/raicem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F326225%2Ff7987331-7a01-4f78-a183-67933541b97a.png</url>
      <title>DEV Community: Cem Ünalan</title>
      <link>https://dev.to/raicem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raicem"/>
    <language>en</language>
    <item>
      <title> 10 Symfony Testing Tips </title>
      <dc:creator>Cem Ünalan</dc:creator>
      <pubDate>Sat, 01 Feb 2020 21:59:32 +0000</pubDate>
      <link>https://dev.to/raicem/10-symfony-testing-tips-1ha9</link>
      <guid>https://dev.to/raicem/10-symfony-testing-tips-1ha9</guid>
      <description>&lt;p&gt;I took part in a project that had a two years old codebase and used Symfony 3.4 as the web framework. It was not the newest and shiniest project but it had a one big advantage: there were tests covering most of the critical actions in the application.&lt;/p&gt;

&lt;p&gt;For the first time in my career I have witnessed how tests give you confidence over a codebase, start saving you time and help you tackle the business requirements.&lt;/p&gt;

&lt;p&gt;Project achieved this with many Symfony functional tests and some unit tests that cover the gaps in between. Total coverage was around 50-52% but critical features coverage was significantly higher and provided enough confidence to add new features without manually testing.&lt;/p&gt;

&lt;p&gt;For those who are coming from an another ecosystem, let me explain what the functional tests in Symfony world mean.&lt;/p&gt;

&lt;p&gt;In Symfony documentation, functionals tests &lt;a href="https://symfony.com/doc/current/testing.html#functional-tests"&gt;are defined&lt;/a&gt; like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Functional tests check the integration of the different layers of an application (from the routing to the views).&lt;/em&gt;“&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They are basically end-to-end tests where you write code that sends an HTTP request to the application. You receive an HTTP response from the app and you do assertions based on that response. However, you do have power to go to the database and assert the changes in the persistance layer which sometimes gives an extra opportunity to check the state.&lt;/p&gt;

&lt;p&gt;I would like to share some of the tips I have accumulated working with Symfony writing functional tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1) Testing with the persistence layer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Probably the first thing you want to achieve while running your functional tests, is to seperate your testing database from your development database. This is done to create a clean slate for your test suite to run. It will allow you to control and create a desired state of the app for your test cases. Also, having a test suite write random data to your development copy of the database is not ideal.&lt;/p&gt;

&lt;p&gt;This generally is achieved by making your Symfony app connect to a different database while running the test suite. Using Symfony 4 or 5, you can define environment variables that are going to be used while testing in a &lt;code&gt;.env.test&lt;/code&gt; file. You should also &lt;a href="https://phpunit.readthedocs.io/en/8.5/configuration.html"&gt;configure&lt;/a&gt; PHPUnit to change the environment variable APP_ENV to &lt;code&gt;test&lt;/code&gt;. Luckily this configuration is done by default when you install &lt;a href="https://github.com/symfony/phpunit-bridge"&gt;Symfony PHPUnit Bridge Component.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For Symfony versions running below 4, you can rely on kernel booting in test mode while running the functional tests. That way, you can define your test specific configation within &lt;code&gt;config_test.yml&lt;/code&gt; files.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2) LiipFunctionalTestBundle&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This &lt;a href="https://github.com/liip/LiipFunctionalTestBundle"&gt;bundle&lt;/a&gt; packs some functional test helpers to write Symfony tests. Sometimes it tries to do too much and gets in your way, but generally it is pleasent to have some things streamlined for writing tests.&lt;/p&gt;

&lt;p&gt;For example, during testing you can simulate logins with a user, load data fixtures, count database queries to test performance regresssions and etc. I would consider installing this bundle when starting testing a new Symfony application.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3) Flushing the database with every test&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Another important topic to cover is when to reset the database during testing. Symfony testing tools does not give you an opinion about this issue but I generally like to refresh the database after each test method. This basically makes the whole test suite look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\BaseTestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_a_registered_user_can_login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Clean slate. Database is empty.&lt;/span&gt;
        &lt;span class="c1"&gt;// Create your world. Create users, roles and data.&lt;/span&gt;
        &lt;span class="c1"&gt;// Execute logic.&lt;/span&gt;
        &lt;span class="c1"&gt;// Assert the outcome.&lt;/span&gt;
        &lt;span class="c1"&gt;// Database is reset.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I find that loading empty fixtures in PHPUnit’s special setUp method is a great way of flushing the database. If you have installed the previously mentioned LiipFunctionalTestBundle, you can install empty fixtures to flush the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseTestCase&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit_Test_Case&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;loadFixtures&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;4) Creating Data&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Starting every test with an empty database, means you have to have some utilities or helpers to create data for testing. These can be creating database model or entity objects.&lt;/p&gt;

&lt;p&gt;Laravel has a very streamlined method with &lt;a href="https://laravel.com/docs/6.x/database-testing#writing-factories"&gt;model factories&lt;/a&gt;. I try to follow a similar approach and create some traits that creates objects that I frequently use in my tests. For example this is a simple trait that creates User entities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\Helpers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;AppBundle\Entity\User&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;trait&lt;/span&gt; &lt;span class="nc"&gt;CreatesUsers&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;makeUser&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;User&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setFirstName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setLastName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setRoles&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ROLE_USER&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setBio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;faker&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;paragraph&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I can then include these traits in TestCases I want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\BaseTestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\Helpers\CreatesUsers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SomeControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;CreatesUsers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_a_registered_user_can_login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createUser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Login as user. Do some tests.&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5) Swap services in a container&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;While very &lt;a href="https://laravel.com/docs/5.8/mocking#mocking-objects"&gt;easy to do so&lt;/a&gt; in a Laravel application, swapping services in the container is a bit tricky when it comes to the Symfony projects. Services in the container are marked private between Symfony 3.4 and 4.1 releases. This means, while writing your tests, you simply cannot access the service from the container and you cannot set another (mock) service.&lt;/p&gt;

&lt;p&gt;While some developers state that during functional tests you should not mock anything, in practice there may be situations where you don’t have a sandbox environment for a 3rd party service and you don’t want to feed these 3rd party services with random test data.&lt;/p&gt;

&lt;p&gt;Luckily as of Symfony 4.1, during testing Symfony will allow you to access the container and change services as you wish.&lt;/p&gt;

&lt;p&gt;You may consider this approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Tests\AppBundle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;AppBundle\Payment\PaymentProcessorClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Tests\BaseTestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentControllerTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;BaseTestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_a_user_can_purchase_product&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$paymentProcessorClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentProcessorClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$paymentProcessorClient&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;once&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'purchase'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$successResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// this is a hack to make the container use the mocked instance after the redirects&lt;/span&gt;
        &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;disableReboot&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContainer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PaymentProcessorClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$paymentProcessorClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But please do note, during functional testing Symfony kernel may boot up couple of times in a single test, basically rebuilding all the dependencies and leaving your mocked service left out. This may be tricky to spot first and I have yet to find an elegant solution to it.&lt;/p&gt;

&lt;p&gt;The hacky way I have come up with is to disable kernel reboot and make sure the same app kernel instance is used during the litetime of that test method. This will ensure that the kernel will not be recompiled and mocked service will not be lost. Make sure this does not create more side effects.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;6) Running SQLite in memory&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;It is very common to use sqlite as the persistence layer during testing since it is very portable and very easy to setup. These qualities also make it very suitable for using in CI/CD environment during testing.&lt;/p&gt;

&lt;p&gt;SQLite is serverless, meaning that the SQLite program will write and read all the data from a file.&lt;/p&gt;

&lt;p&gt;Reading and writing from a file will likely to be come a performance bottleneck during testing as it is an extra I/O operation that you code will have to wait. For that reason, you may use the &lt;a href="https://www.sqlite.org/inmemorydb.html"&gt;in-memory option&lt;/a&gt; for the SQLite. This will write all the data to memory and hopefully make the operations faster.&lt;/p&gt;

&lt;p&gt;While configuring your database in your Symfony app, instead of pointing to a ‘database.sqlite’ file, &lt;a href="https://www.doctrine-project.org/projects/doctrine-dbal/en/2.10/reference/configuration.html"&gt;it is enough to feed it&lt;/a&gt; with ‘:memory:’ keyword.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;7) Running SQLite in memory with tmpfs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Using the in memory option is great but I had a very hard time configuring the in memory option under the old version of the LiipFunctionalTestBundle.&lt;/p&gt;

&lt;p&gt;If you face a similar sitation here is a trick.&lt;/p&gt;

&lt;p&gt;On a Linux system, you can allocate a space in RAM that behaves as a normal file storage space. This feature is called &lt;a href="https://en.wikipedia.org/wiki/Tmpfs"&gt;tmpfs&lt;/a&gt;. Basically you can create a tmpfs folder, put your sqlite database file there and then use that to run your tests on.&lt;/p&gt;

&lt;p&gt;You can also follow a similar approach with MySQL testing, however that may be a little complicated to setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;8) Testing the Elasticsearch layer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Just like connecting to a testing database instance you can connect to a test Elasticsearch instance as well. Or better yet, you can use different index names during testing have a testing/development environment seperation that way.&lt;/p&gt;

&lt;p&gt;While looking easy, testing Elasticsearch can be a struggle in practice. We have strong tools to generate database schemas, create fixtures, populate the database with test data easily. These tools may not exist when it comes down to Elasticsearch and you may have to create your own solutions. It may not be straightforward to start testing right away.&lt;/p&gt;

&lt;p&gt;There are also a problem of indexing new data and that data being available. A commong gotcha is the Elasticsearch’s refresh interval. Generally indexed documents become avaiable for search after the Elasticsearch’s configurable refresh interval. The default value is 1 second and it may trip up your tests randomly if you are not careful.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;9) Using Xdebug filters to speed up coverage report&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Coverage is an important asset when it comes to testing. It should not be treated as just a number, but a way to find untested branches and flows in your code.&lt;/p&gt;

&lt;p&gt;Generating coverage info is generally handled by &lt;a href="https://xdebug.org/docs/code_coverage"&gt;Xdebug&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You’ll notice that running the coverage analysis, generally causes your test suite speed to crumble. This may be a problem in CI/CD environment where each minute is billed.&lt;/p&gt;

&lt;p&gt;Luckily there are some optimizations to be made. When Xdebug generates coverage info for the running tests, it generates coverage info for the every PHP file run in that test. That includes the PHP files residing in the vendor folder, a code that we don’t own.&lt;/p&gt;

&lt;p&gt;Using the Xdebug code coverage filter configuration we can prevent Xdebug to generate coverage for the files that we don’t want and same some significant time.&lt;/p&gt;

&lt;p&gt;How do we generate that filter? Well. PHPUnit &lt;a href="https://phpunit.readthedocs.io/en/8.5/code-coverage-analysis.html"&gt;can do that for us&lt;/a&gt;. You just have to a single to command to create a filter configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phpunit &lt;span class="nt"&gt;--dump-xdebug-filter&lt;/span&gt; build/xdebug-filter.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And feed that configuration file when you run your tests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;phpunit &lt;span class="nt"&gt;--prepend&lt;/span&gt; build/xdebug-filter.php &lt;span class="nt"&gt;--coverage-html&lt;/span&gt; build/coverage-report
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;10) Paralel testing tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Running functional tests can take up significant time. As an example, a test suite with 77 tests and 524 assertions can take up to 3-4 minutes to fully run. This pretty normal considerin with each test you are making bunch of database calls, rendering twig templates, running the crawler on those templates and do some assertions.&lt;/p&gt;

&lt;p&gt;If you open up the activity monitor, you can see that while running tests only single core of your computer is utilized.&lt;/p&gt;

&lt;p&gt;Some paralel testing tools such as &lt;a href="https://github.com/paratestphp/paratest"&gt;paratest&lt;/a&gt; and &lt;a href="https://github.com/liuggio/fastest"&gt;fastest&lt;/a&gt; have come out to use more than single core to execute your tests. While running unit tests with these tools are straightforward, running tests that connect to a database may need some tweaking.&lt;/p&gt;

&lt;p&gt;I was able to utilize 6 cores and 12 threads on my local dev machine to bring down 4 minute test suite times to about 25-30 seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Edit&lt;/strong&gt;: Some very helpful comments appeared on &lt;a href="https://www.reddit.com/r/PHP/"&gt;r/php&lt;/a&gt; when I shared this article. Click &lt;a href="https://www.reddit.com/r/PHP/comments/hchc8o/10_symfony_testing_tips/"&gt;here&lt;/a&gt; to read more tricks and tools.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>symfony</category>
      <category>php</category>
    </item>
  </channel>
</rss>
