【问题标题】:Fail to test the rendered output after a redirect from a DELETE route - Mojolicious从 DELETE 路由重定向后无法测试呈现的输出 - Mojolicious
【发布时间】:2016-10-29 11:40:31
【问题描述】:

我目前扩展了我的测试套件以增加测试覆盖率。我想测试我的控制器及其呈现的 html 输出,但我发现使用 delete 方法时出现问题。让我用一个例子来解释一下。

我有一条路线:

$r->delete('/backups/:id')
  ->to('backup#delete_backup')
  ->name('backup_delete');

指向backup控制器中的以下函数:

sub delete_backup {
    my $self       = shift;
    my $id         = $self->param('id');


    if ( something ) {
        $self->flash( msg => "Backup id $id deleted!" );
    }
    else{
        $self->flash( msg => "Cannot delete, backup id $id not found!" );   
    }
    $self->redirect_to($self->url_for('backup_index'));
}

处理路由backup_index 的方法只显示$msg 并显示一些其他不相关的数据。

接下来,我想测试一下这个方法,所以我写了一个测试:

$t_logged_in->ua->max_redirects(3);
my $page = $t_logged_in->app->url_for( 'backup_delete', id => $backup_id );
$t_logged_in->delete_ok($page)
            ->status_isnt( 404, "Checking: 404 $page" )
            ->status_isnt( 500, "Checking: 500 $page" );

测试通过了。但是现在,我想检查重定向后显示的网页上的文本是否正确。所以我做了以下事情:

$t_logged_in->ua->max_redirects(3);
my $page = $t_logged_in->app->url_for( 'backup_delete', id => $backup_id );
$t_logged_in->delete_ok($page)
            ->status_isnt( 404, "Checking: 404 $page" )
            ->status_isnt( 500, "Checking: 500 $page" )
            ->content_unlike(qr/Cannot delete,/i)
            ->content_like(qr/deleted/i);

测试失败。失败是因为内容是空的,所以匹配照原样完成:

'' =~ /deleted/i;
'' !~ /Cannot delete,/i;

这在这两种情况下当然都是错误的。当然,在浏览器中,重定向工作得很好,我看到了测试中设计的一切。我可以将方法更改为POSTGET,但我想按照 API 的设计方式正确地进行路由。

问题:如何设计测试以使重定向后的内容可以匹配?

对于那些想深入挖掘的人,我提供了 Github 的链接。

【问题讨论】:

    标签: perl redirect testing mojolicious test-more


    【解决方案1】:

    抱歉,还没有人回答这个问题。我曾经试图密切关注堆栈溢出,但我变得懒惰:-P。这是一个非常有趣的问题。

    标准重定向 (301/302) 使用与原始请求相同的动词,除非原始请求是 POST 有趣的是,这种行为并不是真正的意图。重定向应该使用与原始请求相同的请求方法,但POST->GET 重定向是如此普遍,以至于大多数浏览器都添加了此行为,即使它违反了原始定义。然而,有些人真的希望POST 保持为POST,现在它取决于实现。事实上,这变得如此糟糕,以至于 HTTP 添加了响应状态 307/308,它总是重定向为相同的 http 动词(即POST -> POST),甚至认为这已经是旧版本的官方行为,但那艘船有航行。这意味着POST->GET,但DELETE->DELETE是301/302的实际行为。

    这可以在以下一行中演示($_ 在这些一行中是控制器):

    perl -Mojo -E 'del "/delete" => sub { $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
    
    DELETE /delete HTTP/1.1
    Host: 127.0.0.1:62690
    Accept-Encoding: gzip
    User-Agent: Mojolicious (Perl)
    Content-Length: 0
    
    HTTP/1.1 302 Found
    Date: Sun, 18 Sep 2016 03:25:58 GMT
    Server: Mojolicious (Perl)
    Location: /
    Content-Length: 0
    
    DELETE / HTTP/1.1
    Content-Length: 0
    User-Agent: Mojolicious (Perl)
    Host: 127.0.0.1:62690
    Accept-Encoding: gzip
    
    HTTP/1.1 200 OK
    Content-Type: text/html;charset=UTF-8
    Content-Length: 5
    Date: Sun, 18 Sep 2016 03:25:58 GMT
    Server: Mojolicious (Perl)
    
    I got a DELETE
    

    您可以看到,由于我的/ 路由处理了我们得到响应的所有方法,但是请求是DELETE。我看到在您的应用程序中,您重定向到另一个命名路由,其 url 也处理 DELETE。这是您困惑的根源,因为您实际上是在测试中结束的。如果我正确阅读了您的代码,您的重定向实际上是 DELETE /backups/&lt;&lt;id&gt;&gt; -> DELETE /backups

    现在,与想要将 POST 保留为 POST 的人相反,您想要的恰恰相反,您想要从 DELETE 重定向到 GET,因为您试图显示一个响应不是原始资源。这是鲜为人知的 303 响应的定义行为,其中任何请求方法都被重定向到 GET。的确,这是早期浏览器应该坚持的,而不是打破 302。

    在以下示例中,我将响应代码显式修改为 303。

    $ perl -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
    DELETE /delete HTTP/1.1
    User-Agent: Mojolicious (Perl)
    Host: 127.0.0.1:62716
    Accept-Encoding: gzip
    Content-Length: 0
    
    HTTP/1.1 303 See Other
    Location: /
    Content-Length: 0
    Server: Mojolicious (Perl)
    Date: Sun, 18 Sep 2016 03:27:19 GMT
    
    DELETE / HTTP/1.1
    User-Agent: Mojolicious (Perl)
    Accept-Encoding: gzip
    Content-Length: 0
    Host: 127.0.0.1:62716
    
    HTTP/1.1 200 OK
    Content-Type: text/html;charset=UTF-8
    Server: Mojolicious (Perl)
    Content-Length: 5
    Date: Sun, 18 Sep 2016 03:27:19 GMT
    
    I got a DELETE
    

    但是,哎呀,那仍然是DELETE!这是因为 Mojo::UserAgent 中有一个 bug,所以它不能正确处理 303。我建议您仍然对代码进行更改,因为浏览器似乎可以正确处理 303。但是,由于 Mojo::UserAgent 支持 Test::Mojo,您的测试还不能测试该行为。一旦fixed,您将看到它正常工作,就像我在本地分支中的示例一样:

    $ perl -Ilib -Mojo -E 'del "/delete" => sub { $_->res->code(303); $_->redirect_to("/") }; any "/" => { inline => q[I got a <%= $c->req->method %>] }; app->start' get -r -v -M DELETE /delete
    DELETE /delete HTTP/1.1                                                                  
    Content-Length: 0                                                                        
    User-Agent: Mojolicious (Perl)                                                           
    Host: 127.0.0.1:64924                                                                    
    Accept-Encoding: gzip                                                                    
    
    HTTP/1.1 303 See Other                                                                   
    Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
    Location: /                                                                              
    Server: Mojolicious (Perl)                                                               
    Content-Length: 0                                                                        
    
    GET / HTTP/1.1                                                                           
    Content-Length: 0                                                                        
    User-Agent: Mojolicious (Perl)                                                           
    Host: 127.0.0.1:64924                                                                    
    Accept-Encoding: gzip                                                                    
    
    HTTP/1.1 200 OK                                                                          
    Date: Sun, 18 Sep 2016 04:59:37 GMT                                                      
    Content-Type: text/html;charset=UTF-8                                                    
    Server: Mojolicious (Perl)                                                               
    Content-Length: 12                                                                       
    
    I got a GET
    

    要了解有关重定向响应类型的更多信息,请参阅https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_Redirection

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-01
      • 1970-01-01
      • 2015-11-24
      • 2012-02-12
      • 1970-01-01
      • 2020-10-06
      • 2020-08-28
      • 1970-01-01
      相关资源
      最近更新 更多