我在Symfony2 / Doctrine2中使用Behat。现在,我有这个场景,归结为这样的事实:“如果我已登录并且我进入/登录,我应该转到/取而代之”:
@login
Scenario: Go to the login page while being logged in
Given I am logged in
When I go to "/login"
Then I should be on "/"
对于@login,我创建了以下内容:
/**
* @BeforeScenario @login
*/
public function loginUser()
{
$doctrine = $this->getContainer()->get('doctrine');
$userRepository = $doctrine->getRepository('MyTestBundle:User');
$user = $userRepository->find(1); // 1 = id
$token = new UsernamePasswordToken($user, NULL, 'main', $user->getRoles());
$this->getContainer()->get('security.context')->setToken($token);
}
在“当我进入/登录”代码(控制器被调用)时,令牌似乎消失了(不是我想要的):
/**
* @Route("/login", name="login")
*/
public function loginAction()
{
$token = $this->get('security.context')->getToken();
$fd = fopen('/tmp/debug.log', 'a');
fwrite($fd, $token);
// prints 'AnonymousToken(user="anon.", authenticated=true, roles="")'
...
但是在FeatureContext中,它似乎一直存在(我希望它的工作方式)。在“鉴于我登录”中:
/**
* @Given /^I am logged in$/
*/
public function iAmLoggedIn()
{
$token = $this->getContainer()->get('security.context')->getToken();
$fd = fopen('/tmp/debug.log', 'a');
fwrite($fd, $token);
// prints 'UsernamePasswordToken(user="admin", authenticated=true, roles="ROLE_ADMIN")'
...
我跑得像这样:
app/console -e=test behat
我也在控制器中做了这个以确定它的测试:
fwrite($fd, $this->get('kernel')->getEnvironment());
// prints 'test'
有任何线索如何验证用户?我将不得不测试很多管理页面,所以如果我可以将登录挂钩到@BeforeSuite,@ BeforeFeature(或@BeforeScenario ......)以便我不会被阻止,那就太好了。
(关于禁用测试认证机制的建议,或者存根/模拟用户的方法也是受欢迎的。)
答案 0 :(得分:19)
哦,我的。它不起作用,因为您的FeatureContext中的DIC不与您的应用共享 - 您的应用具有单独的内核和DIC。你可以通过Mink得到它。或者,你可以正确地做到: - )
正确的方式意味着,最终用户可以观察到的每个行为部分都应该在* .feature中描述,而不是在FeatureContext中描述。这意味着,如果你想登录用户,你应该简单地用步骤描述它(比如:“我在/登录”,“我填写用户名......”,“我填写密码”和stuf) 。如果你想多次这样做 - 你应该创建一个metastep。
Metasteps只是描述多个其他步骤的步骤,例如 - “我以everzet身份登录”。你可以在这里阅读它们:http://docs.behat.org/guides/2.definitions.html#step-execution-chaining
答案 1 :(得分:1)
以下是我使用的OAuth登录解决方案。经过多次搜索答案并登陆此页面后,我认为分享解决方案会很棒。希望它会帮助别人。
后台:使用HWIOAuthBundle的Symfony2应用程序,连接到某个OAuth2提供程序。
问题:当Behat上下文未与Symfony上下文共享时,如何实现Given I'm logged in
?
<强>解决方案强>:
HWIOAuthBundle使用@buzz
服务对OAuth提供商进行所有API调用。因此,您需要做的就是将Buzz客户端替换为不调用外部服务的实现,但会立即返回结果。这是我的实施:
<?php
namespace Acme\ExampleBundle\Mocks;
use Buzz\Client\ClientInterface;
use Buzz\Message\MessageInterface;
use Buzz\Message\RequestInterface;
class HttpClientMock implements ClientInterface
{
public function setVerifyPeer()
{
return $this;
}
public function setTimeout()
{
return $this;
}
public function setMaxRedirects()
{
return $this;
}
public function setIgnoreErrors()
{
return $this;
}
public function send(RequestInterface $request, MessageInterface $response)
{
if(preg_match('/\/oauth2\/token/', $request->getResource()))
{
$response->setContent(json_encode([
'access_token' => 'valid',
'token_type' => 'bearer',
'expires_in' => 3600
]));
}
elseif(preg_match('/\/oauth2\/me/', $request->getResource()))
{
$response->setContent(json_encode([
'id' => 1,
'username' => 'doctor',
'realname' => 'Doctor Who'
]));
}
else throw new \Exception('This Mock object doesn\'t support this resource');
}
}
下一步是劫持HWIOAuthBundle / Buzz使用的类,并将其替换为上面的实现。我们只需要为测试环境做这件事。
# app/config/config_test.yml
imports:
- { resource: config_dev.yml }
parameters:
buzz.client.class: Acme\ExampleBundle\Mocks\HttpClientMock
最后,您需要将require_previous_session
设置为false以用于测试环境 - 因此我建议将其作为参数传递。
# app/config/security.yml
security:
firewalls:
secured_area:
oauth:
require_previous_session: false
现在你可以像这样实施你的步骤了。
规格:
Feature: Access restricted resource
Scenario: Access restricted resource
Given I'm logged in
When I go to "/secured-area"
Then I should be on "/secured-area"
And the response status code should be 200
实现:
<?php
/**
* @Given /^I\'m logged in$/
*/
public function iMLoggedIn()
{
$this->getSession()->visit($this->locatePath('/login/check-yourOauthProvider?code=validCode'));
}
您传递的代码不相关,您传递的任何内容都可以,因为它没有被检查。您可以在HttpClientMock::send
方法中自定义此行为。
答案 2 :(得分:1)
http://robinvdvleuten.nl/blog/handle-authenticated-users-in-behat-mink/是关于如何创建登录会话和设置Mink会话cookie以便登录Mink会话的简单,干净的文章。这比每次登录用户时使用登录表单要好得多
答案 3 :(得分:0)
可以在这里调用UI层“内部”(在symfony中:与模型交谈)。 对于那里的所有symfony用户,建议使用带有表参数的Given步骤来设置记录而不是夹具。通过这种方式,您可以在一个位置读取场景,并在不必在文件之间跳转的情况下理解它:
鉴于有用户:
|用户名|密码|电子邮件|
| everzet | 123456 | everzet@knplabs.com |
| fabpot | 22 @ 222 | fabpot@symfony.com |