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

时间:2018-07-25 09:06:54

标签: perl testing mojolicious

Mojolicious框架states接下来:

  

可以从Test :: Mojo通过应用程序对象自省应用程序的任何方面(助手,插件,路由等)。

但是,例如当助手$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之外还应保存会话对象

2 个答案:

答案 0 :(得分:2)

要在上一个请求的上下文中测试帮助程序,我编写下一个角色:

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;

答案 1 :(得分:1)

Test::Mojo类无法直接访问会话内容。测试类代表您的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);