Behat 验证 Symfony2 用户
我在 Symfony2 / Doctrine2 中使用 Behat。现在,我的情况可以归结为这样一个事实:“如果我登录并转到 /login,我应该转到 /”:
@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);
}
在“当我转到 /login" 代码(控制器被调用),令牌似乎消失了(不是我想要的):
/**
* @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 ...),这样我就不会被阻止,那就太好了。
(也欢迎关于禁用测试身份验证机制的建议,或者存根/模拟用户的方法。)
I'm using Behat in Symfony2 / Doctrine2. Now, I have this scenario that boils down to the fact that "if I'm logged in and I go to /login, I shoud go to / instead":
@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 "/"
For the @login, I created the following:
/**
* @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);
}
In the "when I go to /login" code (the controller gets called), the token seems gone (not what I intended):
/**
* @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="")'
...
But in the FeatureContext, it seems to stick around (the way I hoped it would work). In the "Given I am logged in":
/**
* @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")'
...
I run behat like this:
app/console -e=test behat
I also did this in the controller to be sure it's test:
fwrite($fd, $this->get('kernel')->getEnvironment());
// prints 'test'
Any clue how to authenticate a user? I will have to test a lot of admin pages, so it would be nice if I could hook the login into @BeforeSuite, @BeforeFeature (or @BeforeScenario ...) so that I don't get blocked.
(Suggestions on disabling the authentication mechanism for testing, or a way to stub/mock a user are also welcome.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
天哪。它不起作用,因为您的 FeatureContext 内的 DIC 不与您的应用程序共享 - 您的应用程序具有单独的内核和 DIC。你可以通过Mink得到它。或者,您可以简单地以正确的方式进行:-)
正确的方式意味着,最终用户可观察到的行为的每个部分都应该在 *.feature 中描述,而不是在 FeatureContext 中。这意味着,如果您想登录用户,您应该简单地用步骤描述它(例如:“我在/登录”,“我填写用户名...”,“我填写密码”等等) 。如果您想多次执行此操作 - 您应该创建一个元步骤。
元步骤只是简单的步骤,描述多个其他步骤,例如 - “我以everzet 身份登录”。您可以在这里阅读有关它们的信息:http://docs.behat。 org/guides/2.definitions.html#step-execution-chaining
Oh my. It doesn't work because the DIC inside your FeatureContext isn't shared with your app - your app has separate kernel and DIC. You can get it through Mink. Or, you can simply do it right way :-)
Right way means, that every part of behavior, that is observable by the enduser, should be described inside *.feature, not inside FeatureContext. It means, that if you want to login a user, you should simply describe it with steps (like: "i am on /login", "and i fill in username ...", "i fill in password" and stuf). If you want to do it in multiple times - you should create a metastep.
Metasteps are simply steps, that describe multiple other steps, for example - "i am logged in as everzet". You could read bout them here: http://docs.behat.org/guides/2.definitions.html#step-execution-chaining
这是我使用过的使用 OAuth 登录的解决方案。经过多次搜索答案并登陆此页面后,我认为分享解决方案会很棒。希望它能帮助某人。
背景:使用 HWIOAuthBundle 的 Symfony2 应用程序,连接到某些 OAuth2 提供商。
问题:当 Behat 上下文未与 Symfony 上下文共享时,如何实现
假设我已登录
?解决方案:
HWIOAuthBundle 使用
@buzz
服务对 OAuth 提供程序进行所有 API 调用。因此,您需要做的就是用您的实现替换 Buzz 客户端,该实现不调用外部服务,而是立即返回结果。这是我的实现:下一步是劫持 HWIOAuthBundle/Buzz 使用的类并将其替换为上面的实现。我们只需要在测试环境中这样做。
最后,您需要将测试环境的
require_previous_session
设置为 false - 因此我建议将其作为参数传递。现在您可以像这样实施您的步骤。
规范:
实现:
您传递的代码不相关,您传递的任何内容都可以,因为它没有被检查。您可以在 HttpClientMock::send 方法中自定义此行为。
Here is an solution for login with OAuth I've used. After number of times of searching for the answer and landing on this page I thought it would be great to share the solution. Hopefully it will help someone.
Background: Symfony2 App using HWIOAuthBundle, hooked up to some OAuth2 provider.
Problem: How do I implement
Given I'm logged in
when Behat context in not shared with Symfony context?Solution:
HWIOAuthBundle uses
@buzz
service for all API calls to OAuth providers. So all you need to do is replace Buzz client with your implementation which doesn't call external services, but returns the result straight away. This is my implementation:Next step is to hijack the class used by HWIOAuthBundle/Buzz and replace it with the implementation above. We need to do it only for test environment.
And finally, you need to set
require_previous_session
to false for test environment - therefore I suggest to pass it as parameter.Now you can implement your step like this.
Specification:
Implementation:
The code you're passing is not relevant, anything you pass will be OK as it's not being checked. You can customise this behaviour in
HttpClientMock::send
method.http://robinvdvleuten.nl/blog/handle-authenticated-users- in-behat-mink/ 是一篇简单、干净的文章,介绍了如何创建登录会话并设置 Mink 会话 cookie 以便记录 Mink 会话这比每次登录用户都使用登录表单要好得多。
http://robinvdvleuten.nl/blog/handle-authenticated-users-in-behat-mink/ is simple, clean article on how to create a login session and set the Mink session cookie so that the Mink session is logged in. This is much better than using the login form every time to login a user.
可以在此处调用 UI 层“内部”的层(在 symfony 中:与模型对话)。
对于所有 symfony 用户,behat 建议使用带有表参数的给定步骤来设置记录而不是固定装置。通过这种方式,您可以在一个地方阅读所有场景并理解它,而无需在文件之间跳转:
假设有用户:
|用户名 |密码 |电子邮件 |
|埃弗泽特 | 123456 | [电子邮件受保护] |
| fabpot | 22@222 | 22@222 [电子邮件受保护] |
It’s ok to call into the layer “inside” the UI layer here (in symfony: talk to the models).
And for all the symfony users out there, behat recommends using a Given step with a tables arguments to set up records instead of fixtures. This way you can read the scenario all in one place and make sense out of it without having to jump between files:
Given there are users:
| username | password | email |
| everzet | 123456 | [email protected] |
| fabpot | 22@222 | [email protected] |