Search code examples
phpsymfonytestingfunctional-testing

Can I create one Client and reuse it for all my functional tests?


tl;dr: Will this potentially keep my tests from working properly?

I'm trying to write functional tests for my Symfony project, and working from examples in The Symfony Book. So far, each method of the test class starts out with the same line of code:

namespace Tests\AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class SomeControllerTest extends WebTestCase
{
    public function testSomethingOnRouteX()
    {
        $client = static::createClient();
        // set up and assert
    }

    public function testSomethingElseOnRouteX()
    {
        $client = static::createClient();
        // different set up and assert
    }
}

I would like to remove this redundant code, but I am not sure if I should do this.

I added a constructor where I created the client.

public function __construct()
{
    parent::__construct();
    $this->client = static::createClient();
}

then in the various test methods I can just use $this->client without needing to create it repeatedly. This seems to work so far (I don't have many tests yet.) But I'm new enough to this framework, and to this type of testing in general that I'm not sure if it will cause problems down the road.


Solution

  • The recommended way to do it is to either use the setUp() method, or the @before hook. Both are called before each test method, so you're safe as the state won't be shared between test cases. Cleanup is also done for you automatically after each test case is run (implemented in the WebTestCase class).

    namespace Tests\AppBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    use Symfony\Bundle\FrameworkBundle\Client;
    
    class SomeControllerTest extends WebTestCase
    {
        /**
         * @var Client
         */
        private $client;
    
        protected setUp()
        {
            $this->client = self::createClient();
        }
    
        public function testSomethingOnRouteX()
        {
            // set up and assert
            $this->client->request('GET', '/something');
        }
    
        public function testSomethingElseOnRouteX()
        {
            // different set up and assert
            $this->client->request('GET', '/something-else');
        }
    }
    

    Alternatively to setUp() you can use the @before hook:

    namespace Tests\AppBundle\Controller;
    
    use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
    use Symfony\Bundle\FrameworkBundle\Client;
    
    class SomeControllerTest extends WebTestCase
    {
        /**
         * @var Client
         */
        private $client;
    
        /**
         * @before
         */
        protected function setUp()
        {
            $this->client = self::createClient();
        }
    
        // ...
    
    }