Wait the light to fall

第四天 - 测试钩子和助手

焉知非鱼

Test::MojoMojolicious 测试工具,有很多方法可以测试 Web 应用程序中的路由(甚至可以在其他 Web 框架中进行测试)。

但是,如果我需要测试的不是路由呢?如果它是一个钩子,一个插件或一个助手怎么办?我们也可以测试所有这些东西!

钩子 #

为了彻底测试钩子,我需要找到配置我的测试用例的方法。我可以指望我的应用程序执行它,并找到正确的路由来测试正确的行为。但是,这会产生更大的测试,集成不同的部分并使测试失败更难调试。我想要的是隔离我正在测试的东西。最好的方法是创建仅测试我想测试的路由。

如果我有一个钩子来记录特殊日志文件的异常,如下所示:

#!/usr/bin/env perl
use Mojolicious::Lite;
# Log exceptions to a separate log file
hook after_dispatch => sub {
    my ( $c ) = @_;
    return unless my $e = $c->stash( 'exception' );
    state $path = $c->app->home->child("exception.log");
    state $log = Mojo::Log->new( path => $path );
    $log->error( $e );
};
app->start;

为了测试这个,一旦我加载了我的应用并创建了一个 Test::Mojo 对象,我就可以自由地为我的应用添加更多配置,包括新路由!这些路由可以为我的测试设置恰当的条件。

# test.pl
use Test::More;
use Test::Mojo;
use Mojo::File qw( path );
my $t = Test::Mojo->new( path( 'myapp.pl' ) );
# Add a route that generates an exception
$t->app->routes->get(
    '/test/exception' => sub { die "Exception" },
);
$t->get_ok( '/test/exception' )->status_is( 500 );
my $log_content = path( 'exception.log' )->slurp;
like $log_content, qr{Exception}, 'exception is logged';
done_testing;

当然,这是技术上测试路由。但是,知道我可以在加载它之后编辑我的应用程序(但在执行任何路由之前)是有用的。我经常生成额外的 Test::Mojo对象,有时使用默认的 Mojo::HelloWorld 应用程序来测试不同的插件。

助手 #

现在,我可以用完全相同的方式测试我的助手程序:设置一个使用我的助手程序并检查结果的新路由。但是,测试助手可以更容易:我可以让应用程序给我一个带有 build_controller 方法的控制器。控制器将具有 Mojo::RequestMojo::Response 对象,因此我可以为我的测试设置条件。

因此,例如,如果我的配置中有一个身份验证令牌,我可以编写一个助手程序来检查我的站点访问者是否正在尝试进行身份验证。

#!/usr/bin/env perl
use Mojolicious::Lite;
# Allow access via tokens
plugin Config => {
    default => {
        tokens => { }, # token => username
    },
};
helper current_user => sub( $c ) {
    my $auth = $c->req->headers->authorization;
    return undef unless $auth;
    my ( $token ) = $auth =~ /^Token\ (\S+)$/;
    return undef unless $token;
    return $c->app->config->{tokens}{ $token };
};

然后,我可以构建一个控制器并设置正确的头来运行我的测试(使用 Test::Mojo 配置覆盖来添加测试令牌),而不是生成 Web 请求来检查我们所有的身份验证边缘情况。

# test.pl
use Test::More;
use Test::Mojo;
use Mojo::File qw( path );
my $token = 'mytoken';
my $t = Test::Mojo->new( path('myapp.pl'), {
    # Add a token as a configuration override
    tokens => { $token => 'preaction' },
} );

my $c = $t->app->build_controller;
is $c->current_user, undef, 'current_user not set';

$c->req->headers->authorization( 'NOTATOKEN' );
is $c->current_user, undef, 'current_user without "Token"';

$c->req->headers->authorization( 'Token NOTFOUND' );
is $c->current_user, undef, 'current_user token incorrect';

$c->req->headers->authorization( "Token $token" );
is $c->current_user, 'preaction', 'current_user correct';

当然,我们仍然需要测试我们想用令牌保护的路由是否受到保护,但是这表明我们的身份验证助手程序工作正常,如果我们的路由出现问题,可能不在这里。

因此,我们的应用程序中的 Web 请求不仅可以测试。当我需要测试钩子时,我可以自己制作测试路由。当我需要测试助手时,我可以通过直接调用它们来实现。测试范围越窄,测试失败的调试就越容易!