我希望在大多数测试之前保留或运行登录。但是如果我尝试将登录代码移动到_之前它不起作用,因为我没有可用的webguy实例。
在多个测试之间保持会话的最佳方法是什么?这是我的代码到目前为止,很乐意得到一些帮助。我用谷歌搜索并检查了文档,但我找不到任何关于会话的东西。
<?php
use \WebGuy;
class ProductCest
{
private $product_id = '1';
public function _before()
{
}
public function _after()
{
}
// tests
public function login(WebGuy $I) {
$I->seeInCurrentUrl('/auth/login');
$I->fillField("//input[@type='email']", "username@email.com");
$I->fillField("//input[@type='password']", "1234");
$I->click('#signIn .submit');
$I->wait(500);
$I->seeInCurrentUrl('/account');
}
/**
* @depends login
*/
public function chooseProduct(WebGuy $I) {
$I->wantTo('go to products and choose one');
$I->amOnPage('/?product=' . $this->client_id);
}
}
答案 0 :(得分:21)
我认为接受的答案是实现它的一种方式,但不是最好的。这样做,当您只需要共享用户会话时,您将始终必须重现登录系统的所有步骤。我认为抓住会话cookie并通过所需的用户记录测试更好。为此,您需要创建一个登录函数,获取cookie,并使您的测试首先取决于登录测试:
<?php
use \AcceptanceTester;
class testingCest
{
private $cookie = null;
public function _before(AcceptanceTester $I)
{
}
public function _after(AcceptanceTester $I)
{
}
// tests
public function login(AcceptanceTester $I)
{
$I->wantTo('entrar al sistema');
$I->amOnPage('/');
$I->seeInCurrentUrl('/admin/login');
$I->fillField('user','perry');
$I->fillField('pass','pass-perry');
$I->click('Login');
$I->see('You\'re logged!');
$this->cookie = $I->grabCookie('your-session-cookie-name');
}
/**
* @depends login
*/
public function listUsers(AcceptanceTester $I)
{
$I->setCookie( 'your-session-cookie-name', $this->cookie );
$I->amOnPage('/admin/users');
$I->seeInCurrentUrl('/admin/users/1');
}
/**
* @depends login
*/
public function listRols(AcceptanceTester $I)
{
$I->setCookie( 'your-session-cookie-name', $this->cookie );
$I->amOnPage('/admin/rols');
$I->seeInCurrentUrl('/admin/rols/1');
}
}
这样,如果登录测试失败,您将无法获得cookie,并且您无法通过其他测试。
我更喜欢这个@depends
注释而不是其他答案中提出的@before
,因为如果您使用@depends
,您将始终执行测试中的代码,并且测试将仅在登录后执行。
还有另一个答案,https://stackoverflow.com/a/41109855/1168804也可能对你有所帮助,因为自编写这个答案以来,Codeception的框架已经发展。
答案 1 :(得分:3)
所有早期答案都是旧的,现在直接在_before方法中完成,该方法将Actor类作为参数。
<?php
namespace Test\Api;
use ApiTester;
class TrainingCest
{
public function _before(ApiTester $I)
{
$I->amLoggedInAs('kgkg');
}
public function _after(ApiTester $I)
{
}
// tests
public function testForLoggedInUser(ApiTester $I)
{
}
public function anotherTestForLoggedInUser(ApiTester $I)
{
}
}
如果您只想为所有CEST文件登录一次,您可以使用全局Registry类实现Registry设计模式(请参阅https://dzone.com/articles/practical-php-patterns/basic/practical-php-patterns-0)以及一些延迟加载。这是我在Actor类中定义的api集成测试的代码(在我的例子中是ApiTester):
public function amLoggedInAs($userLogin)
{
$I = $this;
if (Registry::getInstance()->exists($userLogin)) {
// get data from registry
$storedUserData = Registry::getInstance()->get($userLogin);
$newAccessToken = $storedUserData['accessToken'];
$playerId = $storedUserData['playerId'];
}
else {
// no registry data - log in and save data in registry
$I->tryToLogin($userLogin);
$newAccessToken = $I->grabDataFromResponseByJsonPath('data.newToken');
$playerId = (int)$I->grabDataFromResponseByJsonPath('data.userId');
Registry::getInstance()->set($userLogin, [
'accessToken' => $newAccessToken,
'playerId' => $playerId
]);
}
// finally set headers and some other data
$I->haveHttpHeader('X-Token', $newAccessToken);
$I->havePlayerId($playerId);
}
protected function tryToLogin($userLogin)
{
$I = $this;
$I->wantTo('login into api');
$I->amGoingTo('try to log to API using login and password');
$I->sendPOST('/system/login', ['login' => $userLogin, 'password' => self::getPassword($userLogin)]);
// ...some other checking if user was correctly logged in ...
}
此代码在用户首次登录后基本上将accessToken与一些其他数据存储在Registry中。如果再次调用$ I-&gt; amLoggedInAs('kgkg'),它将从注册表中获取这些值。您可以通过这种方式拥有许多已记录的用户,每个用户每个只记录一次。
您可以使用另一种方法进行自动化而不是自定义标记,逻辑仍然是相同的。
此外,如果您使用的是WebDriver (而非PhpBrowser),则可以使用loadSessionSnapshot和saveSessionSnapshot而不是Registry来获得完全相同的结果。
答案 2 :(得分:2)
<?php
use \WebGuy;
class ProductCest
{
private $product_id = '1';
public function _before()
{
}
public function _after()
{
}
private function executeLogin(WebGuy $I){
$I->seeInCurrentUrl('/auth/login');
$I->fillField("//input[@type='email']", "username@email.com");
$I->fillField("//input[@type='password']", "1234");
$I->click('#signIn .submit');
$I->wait(500);
return $I;
}
// tests
public function login(WebGuy $I) {
$I = $this->executeLogin($I);
$I->seeInCurrentUrl('/account');
}
/**
* @depends login
*/
public function chooseProduct(WebGuy $I) {
$I = $this->executeLogin($I);
$I->wantTo('go to products and choose one');
$I->amOnPage('/?product=' . $this->client_id);
}
}
这应该有用。
答案 3 :(得分:1)
我认为@Sinisa的答案是&#34;工作&#34;一个,但不是&#34;正确&#34;之一。
你想要的不是@depends注释,而是@before。
不同之处在于使用@depends不保留当前上下文,而使用@before保留上下文。
public function foo(WebGuy $I)
{
$I->amOnPage('/foobar');
}
/**
* @depends foo
*/
public function bar(WebGuy $I)
{
$I->seeInCurrentUrl('foobar'); // Wil fail
}
/**
* @before foo
*/
public function baz(WebGuy $I)
{
$I->seeInCurrentUrl('foobar'); // Will pass
}
答案 4 :(得分:0)
应该注意的是,如果您正在测试WordPress,那么WP浏览器模块就会有&#34;糖&#34;登录方法:
loginAsAdmin();
loginAs($username, $password);
答案 5 :(得分:0)
现在,saveSessionSnapshot和loadSessionSnapshot方法使Codeception可以解决此问题。
<?php
// inside AcceptanceTester class:
public function login()
{
// if snapshot exists - skipping login
if ($I->loadSessionSnapshot('login')) return;
// logging in
$I->amOnPage('/login');
$I->fillField('name', 'jon');
$I->fillField('password', '123345');
$I->click('Login');
// saving snapshot
$I->saveSessionSnapshot('login');
}
?>
然后在您的测试课程中,您就可以像这样
public function _before(AcceptanceTester $I)
{
$I->login();
}
答案 6 :(得分:0)
请记住,如果您使用 SaveSessionSnapshot,您必须确保在您的登录完全完成后调用该函数。这意味着如果您的登录需要一些时间(ldap-login 或安全检查),则会在登录完成之前执行 SaveSessionSnapshot 并保存一个空会话。 如果是这样,你必须告诉你的程序等待($I->wait()),或者检查登录是否完全完成。
答案 7 :(得分:0)
在 2021 年,就我而言,就像在 .yml 文件中将 clear_cookies
设置为 false 一样简单..
Codeception 在测试之间删除 cookie,因为作为最佳实践,您应该在测试之间保持登录状态。
但如果你想持久化 cookie,只需声明:
actor: AcceptanceTester
modules:
enabled:
- WebDriver:
clear_cookies: false