3

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

我有一条路线:

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

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

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

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

4

1 回答 1

1

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

标准重定向 (301/302) 使用与原始请求相同的动词,除非原始请求是 aPOST有趣的是,这种行为并不是真正的意图。重定向应该使用与原始请求相同的请求方法,但POST->GET重定向的意图是如此普遍,以至于大多数浏览器都添加了此行为,即使它违反了原始定义。然而,有些人真的希望 aPOST保持 a 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/<<id>>-> 。DELETE /backups

现在,与想要保留POSTas的人POST相反,您在这里想要的是相反的,您想要重定向 from DELETEtoGET因为您试图显示不是原始资源的响应。这是鲜为人知的 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 中存在一个错误,因此它不能正确处理 303。我建议您仍然对代码进行更改,因为浏览器似乎可以正确处理 303。然而,由于 Mojo::UserAgent 支持 Test::Mojo,您的测试还不能测试该行为。修复后,您将看到它正常工作,就像我在本地分支中的示例一样:

$ 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

于 2016-09-18T03:08:15.687 回答