【问题标题】:How to access session data from test?如何从测试中访问会话数据?
【发布时间】:2018-07-25 09:06:53
【问题描述】:

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之外还应该保存会话对象

【问题讨论】:

  • 能否提供一个可运行的测试用例?
  • @daxim:已应用测试脚本。
  • 对于简单的会话,会话数据存储在客户端的 cookie 中,如果没有客户端使用 cookie 的请求,该 cookie 将不可用。
  • @Pradeep 对于 OP 尝试执行的操作,会话数据如何存储并不重要。他希望此时能够访问当前用户请求的会话。我认为这个问题是$t->app 为您提供了应用程序对象,但没有提供最近完成的请求的上下文。但是您的评论非常有用,因为如果它在客户端的 cookie 中,您可以阅读它。 $t->ua毕竟是客户端,在测试中你直接控制它。不过有点hacky。
  • 间接相关,我已经用我的模块 Test::WWW::Mechanize::Catalyst::WithContext 为 Catalyst 解决了这个问题。您可能可以采用类似的方法,或者(根据我的经验,Mojo 有时是这样)解决方案可能更简单但并不明显。

标签: perl testing mojolicious


【解决方案1】:

为了在最后一个请求的上下文中测试助手,我编写了下一个角色:

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;

【讨论】:

  • 我不是 Mojo 专家,但两种选择似乎都可行。第二种解决方案如何更健壮?我可能会在本地摆脱角色和子类 Test::Mojo 来处理它。这样可以减少样板。
  • @simbabque:我不知道。 jberger 说第一个解决方案很丑。
  • 我相信乔尔的话。所以我猜你的第一个解决方案很慢,因为它每次都需要创建一个控制器对象。也可能是其他事情发生在后台,但我对 Mojo 的内部结构一点也不熟悉。如果您的测试运行中有多个 Test::Mojo 实例,则第二种解决方案不是很好。如果你开始在一个进程中运行多个测试,你会遇到麻烦,特别是如果它们并行运行。我将子类化并将 $req_context 设为属性。
【解决方案2】:

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);

【讨论】:

  • 我找到了不同的解决方案。对于给定的上下文,我们可以build_controller。请参阅上面的答案。
猜你喜欢
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-16
相关资源
最近更新 更多