9

我有一些看起来像这样的代码:

use SomeApp;
use Test::WWW::Mechanize::PSGI;                                                                                                                                         
my $mech = Test::WWW::Mechanize::PSGI->new(
    app  => sub { SomeApp->run(@_) },
);
$mech->get_ok('/');

但是,一旦get_ok()被调用,我就会收到以下警告:

PSGI error: failed to listen to port 8080: Address already in use at .../5.18.1/HTTP/Server/PSGI.pm line 94.
HTTP::Server::PSGI::setup_listener('HTTP::Server::PSGI=HASH(0x7fe6622fad60)') called at .../5.18.1/HTTP/Server/PSGI.pm line 54

是的,我正在将该端口用于其他用途。来自Test::WWW::Mechanize::PSGI 的文档

此模块允许您测试 PSGI Web 应用程序,但不需要服务器或发出 HTTP 请求。相反,它将 HTTP 请求对象直接传递给 PSGI。

所以理论上,我不需要指定端口,但我收到了上述警告,并且获取的页面返回 500(它们在浏览器中工作正常)。我错过了什么?

  • 测试::WWW::Mechanize::PSGI 版本 0.35
  • Plack 版本 1.0030
  • 催化剂版本 5.90051

更改MyApp->runMyApp->psgi_app结果:

Can't call method "request" on an undefined value at .../5.18.1/Test/WWW/Mechanize/PSGI.pm line 47.

可以通过以下方式复制此错误:

catalyst.pl MyApp
cd MyApp
# run the test program above
4

2 回答 2

15

Catalyst 的run方法实际上会运行 HTTP 服务器(通过 Plack/PSGI!)进行开发,这不是您想要通过 PSGI 进行测试的结果(不运行服务器)。你需要: app => MyApp->psgi_app,没有额外的sub块,因为psgi_app应该返回 PSGI 应用程序本身。

当您的应用返回不符合 PSGI 规范的内容时,错误消息“Can't call method 'request' on ...”是一个常见错误。该消息已在 git master 上进行了一些改进,但它本质上是一个用户错误,因为您基本上是sub { $app }在它期望的时候返回$app.

有关使用 Catalyst 支持 PSGI 的更多文档,请参阅perldoc Catalyst::PSGI.

于 2013-12-28T10:36:21.313 回答
4

Matt Trout 提到LWP::Protocol::PSGI了一种解决方法。它劫持了 HTTP 来完成这项工作:

use Test::WWW::Mechanize;
use LWP::Protocol::PSGI;
use MyApp;

LWP::Protocol::PSGI->register( MyApp->psgi_app(@_) );
my $mech = Test::WWW::Mechanize->new;

# first GET must be absolute
$mech->get('http://localhost/login');
say $mech->content;

# then we can switch to relative
$mech->get('/login');
say $mech->content;

简而言之,以上或多或少是货物崇拜(因为我不明白为什么第一个版本失败了),但这足以让我继续前进。

于 2013-12-28T10:04:58.287 回答