我可以创建一个客户端并将其重复用于我的所有功能测试吗?

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

tl;dr:这是否会阻止我的测试正常工作?

我正在尝试为我的 Symfony 项目编写功能测试,并使用 The Symfony Book 中的示例。到目前为止,测试的每个方法 class 都以同一行代码开始:

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
    }
}

我想删除这段冗余代码,但我不确定是否应该这样做。

我在创建客户端的地方添加了一个构造函数。

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

然后在各种测试方法中我可以直接使用$this->client而不需要重复创建它。到目前为止这似乎有效(我还没有很多测试。)但我对这个框架和一般的这种类型的测试还不够熟悉,所以我不确定它是否会在未来引起问题。

它可能有效也可能无效,具体取决于您正在测试的内容。

新客户端就像全新安装的浏览器。没有设置 cookie,没有历史记录,没有 actual 页面,等等。

例如,如果您正在测试 auth,如果 testCanNotAccessInternalResourceIfNotLoggedIn 使用仍处于登录状态的客户端,那将非常糟糕,因为 testLogInWithCorrectCredentialsWorks 运行 在它之前,因此失败.当然,您可以确保在访问资源之前注销用户,但创建一个干净的新浏览器实例是最简单且最不容易出错的方法。

如果您尝试这样做,您可能应该改用 setUp-method。重用客户端可能会带来副作用,这是您要尽量避免的事情。如果您的测试开始随机失败,您可能想尝试返回到为每个测试创建一个新客户端。我不会推荐它,但更多的是出于直觉而不是实际的糟糕体验。大多数时候它应该工作正常,但是当你突然重用一个客户端,例如一个不同的设置 header 而它不起作用时,你会很头疼。

我不认为会有巨大的性能提升,因为 ui-tests 无论如何都很慢,所以尝试拥有尽可能少的测试用例可能是更好的方法(寻找测试金字塔,如果你不知道我的意思)如果那是你的目标。

推荐的方法是使用 setUp() 方法或 @before 挂钩。两者都在每个测试方法之前调用,因此您是安全的,因为状态不会在测试用例之间共享。每个测试用例 运行 后也会自动为您完成清理(在 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');
    }
}

作为 setUp() 的替代方法,您可以使用 @before 钩子:

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();
    }

    // ...

}