让我们说在Symfony 3.3中我们有一个默认的控制器,它描绘了“Hello,world!”:
class DefaultController extends Controller
{
public function indexAction() : Response
{
return new Response( 'Hello, world!' );
}
}
如果我想测试它,我只是创建一个WebTestCase并在客户端或爬虫上做一些断言,例如
class DefaultControllerTest extends WebTestCase
{
public function testIndex()
{
$client = static::createClient();
$crawler = $client->request( 'GET', '/route/to/hello-world/' );
$this->assertEquals( 200, $client->getResponse()->getStatusCode() );
$this->assertContains( 'Hello', $crawler->filter( 'body' )->text() );
}
}
这很好用。
假设我们有一些经过单元测试的服务。例如,IdGenerator
服务在我们需要时基于特定算法创建新ID,并且它们只是纯文本:
class IdGenerator
{
public function generateNewId() : string;
}
假设我们通过自动装配将其注入控制器。我们希望控制器能够像Hello, world, on request 8bfcedbe1bf3aa44e0545375f0e52f6b969c50fb!
这样的字符集来自IdGenerator。
class DefaultController extends Controller
{
public function indexAction( IdGenerator $idGenerator ) : Response
{
$id = $idGenerator->generateNewId();
$message = sprintf( 'Hello, world, on request %s!', $id );
return new Response( $message );
}
}
当然,我可以在浏览器中多次重新加载页面,并且每次都会看到新文档随时间变化的文本。
但这不是自动化测试应该世界化的方式。我们应该模拟IdGenerator,因此它返回一个特定的id
来断言:
class DefaultControllerTest extends WebTestCase
{
public function testIndex()
{
$id = 'test-id-test-id-test-id';
$idGenerator = $this->createMock( IdGenerator::class );
$idGenerator->method( 'generateNewId' )->willReturn( $id );
// What do I have to do with $idGenerator now here????
$client = static::createClient();
// Do something else here?
$crawler = $client->request( 'GET', '/admin/flights/search/' );
$this->assertEquals( 200, $client->getResponse()->getStatusCode() );
$this->assertContains( $id, $crawler->filter( 'body' )->text() );
}
}
我已经测试过从内核到客户端获取容器,并在那里设置服务并且不工作:
$id = 'test-id-test-id-test-id';
$idGenerator = $this->createMock( IdGenerator::class );
$idGenerator->method( 'generateNewId' )->willReturn( $id );
$client = static::createClient();
$kernel = $client->getKernel();
$container = $kernel->getContainer();
$container->set( 'My\Nice\Project\Namespace\IdGenerator', $idGenerator );
它仍然会获得自动装配的而不是我想要的(模拟)。
如何设置WebTestCase以便自动装配我的模拟服务?
答案 0 :(得分:2)
简短的回答是你没有。
WebTestCase用于更高级别的测试,有时称为功能测试或集成测试。它们旨在使用实际服务或适当的测试替代方案,例如用于测试的SQLite数据库而不是MySQL或Paypal-sandbox而不是生产服务。如果你想测试一个服务并用mock或stub替换它的依赖关系,你应该编写一个单元测试。
如果您想用虚拟实现替换您的服务,例如一个总是根据输入返回相同的id或散列的,您可以替换config/services_test.yaml
中容器配置中的别名,该别名将在您的应用程序使用测试应用程序环境时使用(默认情况下为WebTestCase) )。您也可以尝试在运行时更改容器,但由于Symfony编译容器然后将其冻结,即不允许对容器进行任何更改,因此可能会非常棘手,并且不是真的建议。
作为进一步的参考,Symfony 4.1提供了一个容器,其中包含所有服务,包括私有服务:https://symfony.com/blog/new-in-symfony-4-1-simpler-service-testing 这可能对您的情况没有帮助,但它显示了如何在WebTestCase测试中与服务容器进行交互。