如何从测试中访问会话数据?

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;