作为标题,我的目标是回滚在Behat功能测试期间做出的任何提交。 我检查了这个answer非常相似,但是它来自两年前,似乎无法做到。
现在有可能和Behat 3一起使用。
我知道使用PHPUnit我可以使用startUp和tearDown方法达到类似的效果。
我尝试使用@BeforeScenario和@AfterScenario注释来启动和回滚事务挂钩,但似乎那个和应用程序没有共享同一个实体管理器实例。
有什么建议吗?
谢谢。
谢谢大家的意见。这里有一些新的考虑因素:
LOAD FIXTURES :是的,它有效。我可以在测试开始之前运行灯具,但问题(我的错误,不提它)是灯具有时需要几分钟才能加载,在测试开始前等待10分钟或更长时间是很烦人的。 / p>
BEGIN / ROLLBACK TRANSACTION :它也有效或似乎有效。我没有收到任何错误,但测试期间写入的数据在结束时仍在我的数据库中。我在标记为@BeforeScenario的方法中添加了第一个,后者在一个用@AfterScenario标记的方法中
$this->kernel->getContainer() ->get('doctrine.orm.entity_manager') ->getConnection() ->beginTransaction(); $this->kernel->getContainer() ->get('doctrine.orm.entity_manager') ->getConnection() ->rollBack();
public function gatherContexts(BeforeScenarioScope $scope) { $environment = $scope->getEnvironment(); $connection = $this->kernel->getContainer()->get('doctrine.orm.entity_manager')->getConnection(); $connection->beginTransaction(); $connection->createSavepoint('tests'); } public function rollback(AfterScenarioScope $scope) { $connection = $this->kernel->getContainer()->get('doctrine.orm.entity_manager')->getConnection(); $connection->rollbackSavepoint('tests'); }
所有这些测试都用于测试我的API REST项目。经过这些考虑后,我认为Behat和我的应用程序并不共享实体管理器的相同实例。您是否能够在测试期间在测试和项目之间共享相同的实例?
答案 0 :(得分:6)
如果您的上下文实现了KernelAwareContext
,那么在@BeforeScenario和@AfterScenario注释方法中,您可以执行
$this->kernel->getContainer()->getDoctrine()->getConnection()->beginTransaction();
$this->kernel->getContainer()->getDoctrine()->getConnection()->rollBack();
假设您只有一个连接并且由em使用它。
您也可以尝试使用$connection->setRollbackOnly()
,但请记住,它会依赖于您的基础数据库。如果你没想到它,Mysql可能会在很多情况下自动提交。
最后还有$connection->createSavepoint('savePointName')
与$connection->rollbackSavepoint('savePointName')
这不在我的脑海中,因此可能需要进行一些调整。
答案 1 :(得分:1)
问题在于Behat使用了Browser-Kit中的客户端,因此您正遭受rebootable client的困扰。 幸运的是,Symfony2扩展从容器中获取客户端,因此我们可以覆盖它。这是对我有用的窍门:
创建一个包装器类:
class NoneRebootableClient extends Client
{
public function __construct(KernelInterface $kernel, array $server = array(), History $history = null, CookieJar $cookieJar = null)
{
parent::__construct($kernel, $server, $history, $cookieJar);
$this->disableReboot();
}
public function setServerParameters(array $parameters)
{
return;
}
}
仅当您具有类似“在每种情况之前,设置身份验证标头”之类的内容时,才需要setServerParameters
覆盖。当Behat在vendor/behatch/contexts/src/HttpCall/Request/BrowserKit.php:resetHttpHeaders
中的每次调用之后重置标头时,我们将在第一次调用后松开auth标头。
注意:这可能会产生意想不到的副作用。
然后为test-env配置服务(test.client
ID很重要,其behat用于客户端查找的ID):
test.client:
class: App\Tests\NoneRebootableClient
public: true
arguments:
- '@kernel'
- []
- '@test.client.history'
- '@test.client.cookiejar'
然后在上下文中使用“之前/之后”方案,如上所述:
/**
* @BeforeScenario
*/
public function startTransaction($event)
{
$this->doctrine->getConnection()->beginTransaction();
}
/**
* @AfterScenario
*/
public function rollbackTransaction($event)
{
$this->doctrine->getConnection()->rollBack();
}
等等,我们是幂等的:)
答案 2 :(得分:0)
使用setUp
方法,您可以开始交易。如果两个方法调用之间没有提交,则可以在tearDown
方法中回滚它。
即使您回滚查询,在生产数据库上启动测试也非常危险。这是使用数据夹具初始化数据库测试的更好方法。如果你不能这样做(我想是这样),你想用生产数据进行测试。使用doctrine:migrations
(或doctrine:schema:create
)将生产数据库架构复制到您的开发环境中,并添加脚本以复制数据。
答案 3 :(得分:0)
我认为“删除”和“创建”架构是您正在寻找的解决方案。
我正在使用Behat3
进行功能测试 - 我正在测试相当复杂的Web应用程序和REST API。我正在使用准备好的灯具,并在场景中添加额外的数据。
您可以设置Behat
上下文来为每个(之前)场景加载灯具 - 这非常有用:
class CustomContext implements Context, KernelAwareContext {
/**
* @param type ScenarioEvent
*
* @BeforeScenario
*/
public function reloadSchema($event)
{
// Note: EntityManager and ClassMetadata is required
// reload Schema
$schemaTool = new SchemaTool($entityManager);
$schemaTool->dropSchema($metadata);
$schemaTool->createSchema($metadata);
}
/**
* @param type ScenarioEvent
*
* @AfterScenario
*/
public function closeConnections($event)
{
// close connection(s)
}
// ...
}
在每个方案Doctrine2
正在删除并创建架构之前。接下来感谢下面的捆绑包,您可以为您的场景加载特定/常用灯具。
我正在使用Behat
灯具的以下配置:
nelmio/alice
和fzaninotto / Faker。多亏了这个你可以在场景中加载灯具:
Given the fixtures file "dummy.yml" is loaded
Given the fixtures file "dummy.yml" is loaded with the persister "doctrine.orm.entity_manager"
Given the following fixtures files are loaded:
| fixtures1.yml |
| fixtures2.yml |
如果您需要更多详细信息,请立即告诉我。