如何从测试中访问会话数据?
How to access session data from test?
Mojolicious framework states下一个:
Any aspect of the application (helpers, plugins, routes, etc.) can be introspected from Test::Mojo through the application object.
但是,例如,当助手 $c->current_user
处理会话时它会失败。
会话数据不可用,我无法通过测试访问它:
$t->app->session # {}
因此$t->app->current_user
也失败了。
如何从测试访问会话数据?
UPD 测试
use Mojo::Base -strict;
use Mojolicious::Lite;
use Test::More;
use Test::Mojo;
get '/set_session' => sub {
my $c = shift;
$c->session->{ user_id } = 1;
$c->render( text => $c->session->{ user_id } );
};
get '/get_session' => sub {
my $c = shift;
$c->render( text => $c->session->{ user_id } );
};
my $t = Test::Mojo->new;
$t->get_ok( '/set_session' )->status_is(200);
is $t->app->session->{ user_id }, 1, 'Session available from test script';
$t->get_ok( '/get_session' )->status_is(200)
->content_is( 1 );
done_testing();
UPD 测试结果
ok 1 - GET /set_session
ok 2 - 200 OK
not ok 3 - Session available from test script
# Failed test 'Session available from test script'
# at t/session.t line 22.
# got: undef
# expected: '1'
ok 4 - GET /get_session
ok 5 - 200 OK
ok 6 - exact match for content
1..6
# Looks like you failed 1 test of 6.
UPD
似乎 Mojo::Test
对象除了 the request and response objects from the previous transaction
之外还应该保存会话对象
Test::Mojo
class 不允许您直接访问会话内容。测试 class 代表您的 Mojolicious 应用程序的客户端,客户端也不能直接访问会话 cookie(好吧,它只是 base64 编码的 JSON,所以它并不完全是秘密,但仍然...... ).
测试会话的“正确”方法是检查应用程序关于会话的行为是否正确,而不仅仅是检查会话是否设置为某个值。这实际上就是您的 /get_session
端点所做的。当然,您不应该只是添加这样的端点进行测试,而应该考虑会话如何满足您的要求。例如。作为 BDD 风格的场景:
Feature: the secret page
there is a secret page that should be only visible to logged-in users.
Background:
Given a user "test:test123"
Given a new client
Scenario: users cannot see the page when they are not logged in
When I visit the /secret page
Then I get a 404 response
Scenario: users can see the page after logging in
Given I log in as "test:test123"
When I visit the /secret page
Then I see "this is the secret"
$t->app->session
不包含会话,因为会话数据已加载到控制器的 stash
。这仅在请求期间存在。特别是 app->session
只是一个委托给当前控制器的助手,而不是应用程序的主要方法。
如果您真的需要查看会话 cookie,这可能是最不疯狂的方法,除了膨胀控制器对象:
my ($session) = grep { $_->name eq $t->app->sessions->cookie_name } $t->ua->cookie_jar->all->@*;
$session = $session->value =~ s/--[^-]+$//r; # strip signature
$session =~ tr/-/=/;
$session = $t->app->sessions->deserialize->(Mojo::Util::b64_decode $session);
为了在上次请求的上下文中测试助手,我写了下一个角色:
package Test::Mojo::Role::Helper;
use Mojo::Base -role;
sub helper {
my( $t ) = @_;
$t->tx->req->cookies( @{ $t->tx->res->cookies } );
$t->app->build_controller( $t->tx );
}
1;
然后用作下一个:
use Test::Mojo;
my $t = Test::Mojo->with_roles( '+Helper' )->new( 'MyApp' );
$t->post_ok( '/login', json => { contact => $user_c, password => $user_p } )
->status_is( 200 );
is $t->helper->uid, 1, "Authorized user has identificator";
is $t->helper->role, 'user', "Authorized user has 'user' privilege";
UPD 更稳健的解决方案
package Test::Mojo::Role::Helper;
use Mojo::Base -role;
my $req_context; # Here is controller object
sub helper { $req_context }
sub hook_context {
my( $t ) = @_;
$t->app->hook( after_dispatch => sub{ $req_context = shift });
$t;
}
1;
测试相同,下一个小区别。构建应用程序时,我们应该挂钩 after_dispatch
事件:
my $t = Test::Mojo
->with_roles( '+Helper' )
->new( 'App' )
->hook_context;
Mojolicious framework states下一个:
Any aspect of the application (helpers, plugins, routes, etc.) can be introspected from Test::Mojo through the application object.
但是,例如,当助手 $c->current_user
处理会话时它会失败。
会话数据不可用,我无法通过测试访问它:
$t->app->session # {}
因此$t->app->current_user
也失败了。
如何从测试访问会话数据?
UPD 测试
use Mojo::Base -strict;
use Mojolicious::Lite;
use Test::More;
use Test::Mojo;
get '/set_session' => sub {
my $c = shift;
$c->session->{ user_id } = 1;
$c->render( text => $c->session->{ user_id } );
};
get '/get_session' => sub {
my $c = shift;
$c->render( text => $c->session->{ user_id } );
};
my $t = Test::Mojo->new;
$t->get_ok( '/set_session' )->status_is(200);
is $t->app->session->{ user_id }, 1, 'Session available from test script';
$t->get_ok( '/get_session' )->status_is(200)
->content_is( 1 );
done_testing();
UPD 测试结果
ok 1 - GET /set_session
ok 2 - 200 OK
not ok 3 - Session available from test script
# Failed test 'Session available from test script'
# at t/session.t line 22.
# got: undef
# expected: '1'
ok 4 - GET /get_session
ok 5 - 200 OK
ok 6 - exact match for content
1..6
# Looks like you failed 1 test of 6.
UPD
似乎 Mojo::Test
对象除了 the request and response objects from the previous transaction
Test::Mojo
class 不允许您直接访问会话内容。测试 class 代表您的 Mojolicious 应用程序的客户端,客户端也不能直接访问会话 cookie(好吧,它只是 base64 编码的 JSON,所以它并不完全是秘密,但仍然...... ).
测试会话的“正确”方法是检查应用程序关于会话的行为是否正确,而不仅仅是检查会话是否设置为某个值。这实际上就是您的 /get_session
端点所做的。当然,您不应该只是添加这样的端点进行测试,而应该考虑会话如何满足您的要求。例如。作为 BDD 风格的场景:
Feature: the secret page
there is a secret page that should be only visible to logged-in users.
Background:
Given a user "test:test123"
Given a new client
Scenario: users cannot see the page when they are not logged in
When I visit the /secret page
Then I get a 404 response
Scenario: users can see the page after logging in
Given I log in as "test:test123"
When I visit the /secret page
Then I see "this is the secret"
$t->app->session
不包含会话,因为会话数据已加载到控制器的 stash
。这仅在请求期间存在。特别是 app->session
只是一个委托给当前控制器的助手,而不是应用程序的主要方法。
如果您真的需要查看会话 cookie,这可能是最不疯狂的方法,除了膨胀控制器对象:
my ($session) = grep { $_->name eq $t->app->sessions->cookie_name } $t->ua->cookie_jar->all->@*;
$session = $session->value =~ s/--[^-]+$//r; # strip signature
$session =~ tr/-/=/;
$session = $t->app->sessions->deserialize->(Mojo::Util::b64_decode $session);
为了在上次请求的上下文中测试助手,我写了下一个角色:
package Test::Mojo::Role::Helper;
use Mojo::Base -role;
sub helper {
my( $t ) = @_;
$t->tx->req->cookies( @{ $t->tx->res->cookies } );
$t->app->build_controller( $t->tx );
}
1;
然后用作下一个:
use Test::Mojo;
my $t = Test::Mojo->with_roles( '+Helper' )->new( 'MyApp' );
$t->post_ok( '/login', json => { contact => $user_c, password => $user_p } )
->status_is( 200 );
is $t->helper->uid, 1, "Authorized user has identificator";
is $t->helper->role, 'user', "Authorized user has 'user' privilege";
UPD 更稳健的解决方案
package Test::Mojo::Role::Helper;
use Mojo::Base -role;
my $req_context; # Here is controller object
sub helper { $req_context }
sub hook_context {
my( $t ) = @_;
$t->app->hook( after_dispatch => sub{ $req_context = shift });
$t;
}
1;
测试相同,下一个小区别。构建应用程序时,我们应该挂钩 after_dispatch
事件:
my $t = Test::Mojo
->with_roles( '+Helper' )
->new( 'App' )
->hook_context;