【问题标题】:How do we unit test a Mojolicious controller?我们如何对 Mojolicious 控制器进行单元测试?
【发布时间】:2011-07-26 02:03:07
【问题描述】:

我们创建了以下简单的Mojolicious 控制器:

package SampleApp::Pages;

# $Id$

use strict;
use warnings;

our $VERSION = '0.01';

use Mojo::Base 'Mojolicious::Controller';

sub home {
    my $self = shift;

    $self->render( 'title' => 'Home' );

    return;
}

sub contact {
    my $self = shift;

    $self->render( 'title' => 'Contact' );

    return;
}

sub about {
    my $self = shift;

    $self->render( 'title' => 'About' );

    return;
}

1;

对应的单元测试如下:

package Test::SampleApp::Pages;

# $Id$

use strict;
use warnings;

our $VERSION = '0.01';

use Carp;
use English '-no_match_vars';
use Readonly;
use Test::Mojo;
use Test::Most;

use base 'Test::Class';

Readonly my $SERVER_OK => 200;

sub startup : Tests(startup) {
    eval {
        require SampleApp;

        SampleApp->import;

        1;
    } or Carp::croak($EVAL_ERROR);

    return;
}

sub get_home : Tests(4) {
    my $test = shift;
    my $mojo = $test->mojo;

    $mojo->get_ok('/pages/home')->status_is($SERVER_OK);

    $mojo->text_is(
        'title',
        $test->base_title . ' | Home',
        '... and should have the right title'
    );

    $mojo->content_like(
        qr/<body>(?:\s*\S+\s*)+<\/body>/msx,
        '... and should have a non-blank body'
    );

    return;
}

sub get_contact : Tests(3) {
    my $test = shift;
    my $mojo = $test->mojo;

    $mojo->get_ok('/pages/contact')->status_is($SERVER_OK);

    $mojo->text_is(
        'title',
        $test->base_title . ' | Contact',
        '... and should have the right title'
    );

    return;
}

sub get_about : Tests(3) {
    my $test = shift;
    my $mojo = $test->mojo;

    $mojo->get_ok('/pages/about')->status_is($SERVER_OK);

    $mojo->text_is(
        'title',
        $test->base_title . ' | About',
        '... and should have the right title'
    );

    return;
}

sub base_title {
    my ( $self, $base_title ) = @_;

    if ( defined $base_title ) {
        $self->{base_title} = $base_title;
    }

    return $self->{base_title};
}

sub mojo {
    my ( $self, $mojo ) = @_;

    if ( defined $mojo ) {
        $self->{mojo} = $mojo;
    }

    return $self->{mojo};
}

sub setup : Tests(setup) {
    my $test = shift;

    $test->base_title('Mojolicious Sample App');

    $test->mojo( Test::Mojo->new( app => 'SampleApp', max_redirects => 1 ) );

    return;
}

1;

对我们来说,这更像是功能测试而不是单元测试

有没有办法调用控制器的home 方法并测试它的输出而不需要通过Test::Mojo 启动服务器实例?

【问题讨论】:

    标签: perl testing tdd mojolicious


    【解决方案1】:

    要测试控制器的接线,请使用如下代码。

    我们从熟悉的前题开始t/pages.t

    use Mojolicious;
    use Test::More;
    

    现在创建SampleApp::Pages 的测试子类,记录对render 的调用。

    package TestingPages;
    use Mojo::Base 'SampleApp::Pages';
    
    has 'render_called';
    has 'render_arg';
    
    sub render {
      my($self,%arg) = @_;
      $self->render_called(1);
      $self->render_arg({ %arg });
    }
    

    你的问题使用了Test::Class,所以继续那个主题。

    package Test::SampleApp::Pages;
    
    use base 'Test::Class';
    use Test::More;
    

    请注意,不带参数的 die 会传播最近的异常,因此您不必显式编写 $@

    sub startup : Test(startup) {
      eval { require SampleApp::Pages; SampleApp::Pages->import; 1 } or die;
    }
    

    setup 中,实例化测试子类,将其连接到 Mojolicious 实例,然后关闭日志记录。

    sub setup : Test(setup) {
      my($self) = @_;
    
      my $c = TestingPages->new(app => Mojolicious->new);
      $c->app->log->path(undef);
      $c->app->log->level('fatal');
      $self->{controller} = $c;
    }
    

    在家测试中,调用控制器的home方法,查看结果。

    sub home : Tests(2) {
      my($self) = @_;
      my $c = $self->{controller};
      $c->home;
      is $c->render_called, 1, "render called";
      is $c->render_arg->{title}, "Home", "correct title arg";
    }
    

    最后,运行你的测试。

    package main;
    Test::SampleApp::Pages->runtests;
    

    输出:

    $ ./sampleapp.pl 测试
    从“/tmp/sampleapp/t”运行测试。
    t/pages.t .. 好的
    所有测试成功。
    文件=1,测试=2,1 挂钟秒(0.03 usr 0.02 sys + 0.24 cusr 0.03 csys = 0.32 CPU)
    结果:通过

    现在您已经了解了如何做到这一点,问题是是否值得所有的麻烦。控制器应该是简单的接线。考虑一下控制器中的任何复杂性是否真的属于测试更直接的模型。

    【讨论】:

    • 我不熟悉Test::Class。对于其他不熟悉它的人来说,值得注意的是 - 这是为了理解这里使用的 sub startup : Test(startup) {...} 等成语而需要查看的模块。
    猜你喜欢
    • 2013-05-31
    • 2012-04-24
    • 2018-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多